The PropertyAccess Component

    Note

    If you install this component outside of a Symfony application, you mustrequire the file in your code to enable the classautoloading mechanism provided by Composer. Readthis article for more details.

    Usage

    The entry point of this component is thePropertyAccess::createPropertyAccessorfactory. This factory will create a new instance of the class with thedefault configuration:

    1. use Symfony\Component\PropertyAccess\PropertyAccess;
    2.  
    3. $propertyAccessor = PropertyAccess::createPropertyAccessor();

    You can read an array with thePropertyAccessor::getValuemethod. This is done using the index notation that is used in PHP:

    1. // ...
    2. $person = [
    3. 'first_name' => 'Wouter',
    4. ];
    5.  
    6. var_dump($propertyAccessor->getValue($person, '[first_name]')); // 'Wouter'
    7. var_dump($propertyAccessor->getValue($person, '[age]')); // null

    As you can see, the method will return null if the index does not exist.But you can change this behavior with themethod:

    1. // ...
    2. $propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
    3. ->enableExceptionOnInvalidIndex()
    4. ->getPropertyAccessor();
    5.  
    6. $person = [
    7. 'first_name' => 'Wouter',
    8. ];
    9.  
    10. // instead of returning null, the code now throws an exception of type
    11. // Symfony\Component\PropertyAccess\Exception\NoSuchIndexException
    12. $value = $propertyAccessor->getValue($person, '[age]');

    You can also use multi dimensional arrays:

    1. // ...
    2. $persons = [
    3. [
    4. 'first_name' => 'Wouter',
    5. ],
    6. [
    7. 'first_name' => 'Ryan',
    8. ]
    9. ];
    10.  
    11. var_dump($propertyAccessor->getValue($persons, '[0][first_name]')); // 'Wouter'
    12. var_dump($propertyAccessor->getValue($persons, '[1][first_name]')); // 'Ryan'

    Reading from Objects

    The getValue() method is a very robust method, and you can see all of itsfeatures when working with objects.

    To read from properties, use the "dot" notation:

    1. // ...
    2. $person = new Person();
    3. $person->firstName = 'Wouter';
    4.  
    5. var_dump($propertyAccessor->getValue($person, 'firstName')); // 'Wouter'
    6.  
    7. $child = new Person();
    8. $child->firstName = 'Bar';
    9. $person->children = [$child];
    10.  
    11. var_dump($propertyAccessor->getValue($person, 'children[0].firstName')); // 'Bar'

    Caution

    Accessing public properties is the last option used by PropertyAccessor.It tries to access the value using the below methods first before usingthe property directly. For example, if you have a public property thathas a getter method, it will use the getter.

    Using Getters

    The getValue() method also supports reading using getters. The method willbe created using common naming conventions for getters. It camelizes theproperty name (first_name becomes FirstName) and prefixes it withget. So the actual method becomes getFirstName():

    And it doesn't even stop there. If there is no getter found, the accessor willlook for an isser or hasser. This method is created using the same way asgetters, this means that you can do something like this:

    1. // ...
    2. class Person
    3. {
    4. private $author = true;
    5. private $children = [];
    6.  
    7. public function isAuthor()
    8. {
    9. return $this->author;
    10. }
    11.  
    12. public function hasChildren()
    13. {
    14. return 0 !== count($this->children);
    15. }
    16. }
    17.  
    18. $person = new Person();
    19.  
    20. if ($propertyAccessor->getValue($person, 'author')) {
    21. var_dump('He is an author');
    22. if ($propertyAccessor->getValue($person, 'children')) {
    23. var_dump('He has children');
    24. }

    This will produce: He is an author

    Accessing a non Existing Property Path

    New in version 4.3: The method was introduced inSymfony 4.3.

    By default a is thrown if the property path passed to PropertyAccessor::getValuedoes not exist. You can change this behavior using themethod:

    1. // ...
    2. class Person
    3. {
    4. public $name;
    5. }
    6.  
    7. $person = new Person();
    8.  
    9. $propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
    10. ->disableExceptionOnInvalidPropertyPath()
    11. ->getPropertyAccessor();
    12.  
    13. // instead of throwing an exception the following code returns null
    14. $value = $propertyAccessor->getValue($person, 'birthday');

    The getValue() method can also use the magic __get() method:

    1. // ...
    2. class Person
    3. {
    4. private $children = [
    5. 'Wouter' => [...],
    6. ];
    7.  
    8. public function __get($id)
    9. {
    10. return $this->children[$id];
    11. }
    12. }
    13.  
    14. $person = new Person();
    15.  
    16. var_dump($propertyAccessor->getValue($person, 'Wouter')); // [...]

    Magic __call() Method

    At last, getValue() can use the magic __call() method, but you need toenable this feature by using :

    1. // ...
    2. class Person
    3. {
    4. private $children = [
    5. 'wouter' => [...],
    6. ];
    7.  
    8. public function __call($name, $args)
    9. {
    10. $property = lcfirst(substr($name, 3));
    11. if ('get' === substr($name, 0, 3)) {
    12. return isset($this->children[$property])
    13. ? $this->children[$property]
    14. : null;
    15. } elseif ('set' === substr($name, 0, 3)) {
    16. $value = 1 == count($args) ? $args[0] : null;
    17. $this->children[$property] = $value;
    18. }
    19. }
    20. }
    21.  
    22. $person = new Person();
    23.  
    24. // enables PHP __call() magic method
    25. $propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
    26. ->enableMagicCall()
    27. ->getPropertyAccessor();
    28.  
    29. var_dump($propertyAccessor->getValue($person, 'wouter')); // [...]

    Caution

    The __call() feature is disabled by default, you can enable it by callingPropertyAccessorBuilder::enableMagicCallsee .

    The PropertyAccessor class can do more than just read an array, it canalso write to an array. This can be achieved using thePropertyAccessor::setValuemethod:

    1. // ...
    2. $person = [];
    3.  
    4. $propertyAccessor->setValue($person, '[first_name]', 'Wouter');
    5.  
    6. var_dump($propertyAccessor->getValue($person, '[first_name]')); // 'Wouter'
    7. // or
    8. // var_dump($person['first_name']); // 'Wouter'

    Writing to Objects

    The setValue() method has the same features as the method. Youcan use setters, the magic __set() method or properties to set values:

    You can also use __call() to set values but you need to enable the feature,see Enable other Features:

    1. // ...
    2. class Person
    3. {
    4. private $children = [];
    5.  
    6. public function __call($name, $args)
    7. {
    8. $property = lcfirst(substr($name, 3));
    9. if ('get' === substr($name, 0, 3)) {
    10. return isset($this->children[$property])
    11. ? $this->children[$property]
    12. : null;
    13. $value = 1 == count($args) ? $args[0] : null;
    14. $this->children[$property] = $value;
    15. }
    16. }
    17.  
    18. }
    19.  
    20. $person = new Person();
    21.  
    22. // Enable magic __call
    23. $propertyAccessor = PropertyAccess::createPropertyAccessorBuilder()
    24. ->enableMagicCall()
    25. ->getPropertyAccessor();
    26.  
    27. $propertyAccessor->setValue($person, 'wouter', [...]);
    28.  
    29. var_dump($person->getWouter()); // [...]

    The PropertyAccessor class allows to update the content of arrays stored inproperties through adder and remover methods:

    1. // ...
    2. class Person
    3. {
    4. /**
    5. * @var string[]
    6. */
    7. private $children = [];
    8.  
    9. public function getChildren(): array
    10. {
    11. return $this->children;
    12. }
    13.  
    14. public function addChild(string $name): void
    15. {
    16. $this->children[$name] = $name;
    17. }
    18.  
    19. public function removeChild(string $name): void
    20. {
    21. unset($this->children[$name]);
    22. }
    23. }
    24.  
    25. $person = new Person();
    26. $propertyAccessor->setValue($person, 'children', ['kevin', 'wouter']);
    27.  
    28. var_dump($person->getChildren()); // ['kevin', 'wouter']

    The PropertyAccess component checks for methods called add<SingularOfThePropertyName>()and remove<SingularOfThePropertyName>(). Both methods must be defined.For instance, in the previous example, the component looks for the addChild()and removeChild() methods to access to the children property. is used to find the singular of a property name.

    If available, adder and remover methods have priority over a setter method.

    When you want to check whetherPropertyAccessor::getValuecan safely be called without actually calling that method, you can useinstead:

    1. $person = new Person();
    2.  
    3. if ($propertyAccessor->isReadable($person, 'firstName')) {
    4. // ...
    5. }

    The same is possible for PropertyAccessor::setValue:Call themethod to find out whether a property path can be updated:

    1. $person = new Person();
    2.  
    3. if ($propertyAccessor->isWritable($person, 'firstName')) {
    4. // ...
    5. }

    Mixing Objects and Arrays

    You can also mix objects and arrays:

    1. // ...
    2. class Person
    3. {
    4. public $firstName;
    5. private $children = [];
    6.  
    7. public function setChildren($children)
    8. {
    9. $this->children = $children;
    10. }
    11.  
    12. public function getChildren()
    13. {
    14. return $this->children;
    15. }
    16. }
    17.  
    18. $person = new Person();
    19.  
    20. $propertyAccessor->setValue($person, 'children[0]', new Person);
    21. // equal to $person->getChildren()[0] = new Person()
    22.  
    23. $propertyAccessor->setValue($person, 'children[0].firstName', 'Wouter');
    24. // equal to $person->getChildren()[0]->firstName = 'Wouter'
    25.  
    26. var_dump('Hello '.$propertyAccessor->getValue($person, 'children[0].firstName')); // 'Wouter'
    27. // equal to $person->getChildren()[0]->firstName

    Enable other Features

    The PropertyAccessor can beconfigured to enable extra features. To do that you could use the:

    Or you can pass parameters directly to the constructor (not the recommended way):

    1. $propertyAccessor = new PropertyAccessor(true); // this enables handling of magic __call