Tim Nagel

A place to experiment

Using PropertyPath on Your Own Objects

Something that comes up every so often is how to convert the name of a property into a getter or setter, and generally the solution proposed is something like the following.

1
2
3
4
<?php

$accessor = 'get' . ucfirst($property);
$object->$accessor();

While this might be an acceptable method, there are more elegant solutions, one of which is using the PropertyPath utility provided by the Symfony2 Form component.

The PropertyPath utility provides more advanced functionality, which will search for a getter, isser or hasser method, then fall back to trying to access the property itself.

Consider the following object:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php

class Bar
{
    public $patrons = 0;
    protected $closed = false;

    /**
     * Is the bar closed?
     */
    public function isClosed()
    {
        return $this->closed;
    }

    /**
     * Returns the number of patrons at the bar
     * unless it is closed.
     */
    public function getPatrons()
    {
        return $this->closed ? 0 : $this->patrons;
    }

    // ... more cool stuff ...
}

Should you need to access information on this object without knowing in advance which properties you’d like to call, PropertyPath can help you out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

use Symfony\Component\Form\Util\PropertyPath;

$bar = new Bar();

/**
 * Check if the bar is closed, using isClosed
 */
$property = 'closed';
$path = new PropertyPath($property);

$closed = $path->getValue($bar);

/**
 * How many patrons are in attendance?
 *
 * Will return the number of patrons or 0 if the bar
 * is closed.
 */
$property = 'patrons';
$path = new PropertyPath($property);

$patrons = $path->getValue($bar);

Chaining calls

Another feature of the PropertyPath utility is that it will let you chain calls down an object graph. Consider you wanted to make a call that would be converted to $bar->getPatrons()->getFirst()->getName(), you could use the property path patrons.first.name when constructing the PropertyPath.