What I Want To Achieve
- When coding a project, at times (or most of it?) some classes might have more than 3 fields (for whatever reason it suits you)
- So instead of each time writing and repeating setters and getters (accessor methods), I would like to have a piece of reusable code for all my classes without me ever writing a single line of code for accessors. (‘ever’ as in ‘very very rarely’)
- Now, we also have to take into consideration that some fields might be only get-able or only set-able – (our re-usable piece of code should cater for this)
So how to achieve this?
- Using PHP’s magic methods __get() and __set() coupled with Reflection. This will somehow imitate a Property as used in the context of Csharp or JAVA.
- Design-wise, I will provide TWO approaches using either Trait or Inheritance
First thing first, let’s understand some concepts..
What are Field and Property in the context of PHP
From PHP online doc, it defines a property as:
Class member variables are called “properties”. You may also see them referred to using other terms such as “attributes” or “fields”
Let’s take a simple example:
class Person { ....private $name; ....public function setName($name_provided) //setter method ....{ ........$this->name = $name_provided; ....} ....public function getName() //getter method ....{ ........return $this->name; ....} }//end class
In the code example above, in PHP:
- the class variable $name is called a field or a property
- the class methods setName() and getName() are called accessor methods which otherwise are known as setter and getter methods respectively
To use this class, I would do:
$obj = new Person();
$obj->setName(“Wasseem”);
echo ‘My name is: ‘. $obj->getName(); //will print: My name is Wasseem
What are Field and Property in a C# (csharp) context
If you do C# (or even JAVA), these two terminologies are different. Let me explain..
Let’s try to translate PHP code into C# code:
class Person { ....private String name; ....public String Name ....{ ........get ........{ ............return this.name; ........} ........set ........{ ............this.name = value; ........} ....}//end Name }//end class
In this C# example:
- the class variable name (with the small letter ‘n’) is called a field
- the class method Name (with a Capital letter ‘N’) is known as a Property and it acts as a single call to handle both accessor methods setter/getter
So in C#, you define a field. Then to provide it’s corresponding accessor methods in a simple and elegant way is to define a single method known and called as Property which will have the same naming as the field BUT with the starting letter being in Capital letter.
To use this class, I would do something like:
Person obj = new Person();
obj.name = “Wasseem”;
Console.WriteLine( ‘My name is: ‘ + obj.name ); //will print: My name is Wasseem
What I Want To Point Out..
What I want to point out is that if in C# we can quickly set and get a field by just using a one way call in the form ObjectInstance.fieldName, so why not in PHP we do something similar like $ObjectInstance->field_name?
Is it possible?
YES it is and I’m going to show you how! + I am going a step further in making a re-usable component to handle/generate your dynamically generated PHP properties!
SOLN 1 – Generate Accessor Methods Dynamically in PHP using Inheritance
Let’s see the whole re-usable code:
class ParentClass { ....public function __get($property) ....{ ........$method = 'get' . ucfirst($property); //camelCase() method name ........if( method_exists( $this, $method ) ) ........{ ............$reflection = new ReflectionMethod($this, $method); ............if (!$reflection->isPublic()) ................throw new RuntimeException("The called method is not public."); ........} ........if (property_exists($this, $property)) ........{ ............$reflectedProperty = new ReflectionProperty($this, $property); ............$reflectedProperty->setAccessible(true); ............return $reflectedProperty->getValue($this); ........} ....} ....public function __set($property, $value) ....{ ........$method = 'set' . ucfirst($property); //camelCase() method name ........if( method_exists( $this, $method ) ) ........{ ............$reflection = new ReflectionMethod($this, $method); ............if (!$reflection->isPublic()) ................throw new RuntimeException("The called method is not public."); ........} ........if (property_exists($this, $property)) ........{ ............$reflectedProperty = new ReflectionProperty($this, $property); ............$reflectedProperty->setAccessible(true); ............return $reflectedProperty->setValue($this, $value); ........} ....} }//end class
And to use it in any of your classes, you would do something like:
class MyName extends ParentClass { ....private $name; ....public function sayName() ....{ ........echo 'Hello my name is: ' . $this->name; ....} }//end class MyName class MyAddress extends ParentClass { ....private $address; ....public function sayAddress() ....{ ........echo 'Hello my address is: ' . $this->address; ....} }//end class MyAddress
And then you would call it somewhat like:
$obj = new MyName(); $obj->name = "Wasseem"; $obj->sayName(); echo 'yes indeed his name is: '. $obj->name; $obj2 = new MyAddress(); $obj2->address = "Moka"; $obj2->sayAddress(); echo 'yes indeed his address is: '. $obj2->address;
The OUTPUT will be:
Hello my name is: Wasseem
yes indeed his name is: WasseemHello my address is: Moka
yes indeed his address is: Moka
Note:
- I used the check !$reflection->isPublic() so that if at anytime you want a property’s setter or getter method to not be accessible, you could just include the definition private function getName() {} in your child class and hence you will not be able to do get $obj->name;
QUESTION: Why did I use a 2nd Reflection call to access the Fields of the Child Class from the Parent Class?
You could argue that the parent class should be able to access the child class property, by doing it like:
public function __get($property) { ....$method = 'get' . ucfirst($property); //camelCase() method name ....if( method_exists( $this, $method ) ) ....{ ........$reflection = new ReflectionMethod($this, $method); ........if (!$reflection->isPublic()) ............throw new RuntimeException("The called method is not public."); ....} ....if (property_exists($this, $property)) ....{ ........return $this->{$property}; ....} }
It turns out that the answer is NO. If you do it that way, you will get the exception below.
THOUGHT: Is this a downcasting that is being done?
Notice: Undefined property: MyName::$name in class file MyName.php line
This is why you should use Reflection.
SOLN 2 – Generate Accessor Methods Dynamically in PHP using Trait
Let’s see the whole re-usable code for the Trait approach:
trait PropGeneratorTrait { ....public function __get($property) ....{ ........$method = 'get' . ucfirst($property); //camelCase() method name ........if( method_exists( $this, $method ) ) ........{ ............$reflection = new ReflectionMethod($this, $method); ............if (!$reflection->isPublic()) ................throw new RuntimeException("The called method is not public."); ....} ........if (property_exists($this, $property)) ............return $this->{$property}; ....} ....public function __set($property, $value) ....{ ........$method = 'set' . ucfirst($property); //camelCase() method name ........if( method_exists( $this, $method ) ) ........{ ............$reflection = new ReflectionMethod($this, $method); ............if (!$reflection->isPublic()) ................throw new RuntimeException("The called method is not public."); ........} ........if (property_exists($this, $property)) ............$this->$property = $value; ....} }
And to use it in any of your classes, you would do something like:
class MyName { ....use PropGeneratorTrait; ....private $name; ....public function sayName() ....{ ........echo 'Hello my name is: ' . $this->name; ....} }
And then you would call it somewhat like:
$obj = new MyName();
$obj->name = “Wasseem”;
$obj->sayName();
echo ‘yes indeed his name is: ‘. $obj->name;
When should you use Trait or Inheritance?
- This will depend entirely on your project needs. For example if you are going to encounter the possibility of going multiple inheritance (which is not allowed in PHP), you should opt for the Trait solution. Otherwise, you could choose Inheritance.
- Also note that the implementation for the Trait approach uses one less Reflection class and hence results in fewer lines of code than the Inheritance one
A Disadvantage Of Using Auto Dynamically Properties This Way
=> When using a full-blown IDE like PHPStorm, you will NOT see those class fields in auto-completion.
Conclusion
We have seen that we can use two reusable approaches, Trait & Inheritance, in minimising our time to write complete setter/getter methods by making use of PHP’s magic methods and its powerful Reflection classes. And that you should use the Trait approach if you judge that you are going to have a multiple inheritance scenario, since multiple inheritance is not possible in PHP.
Over To You – Give Me Your Feedback & Opinion
Are you inline with how I did it? Do you see any downside or may be you have a better/different approach? Please do let me know using the comment form below..Thanks!
That is exactly what i am looking for at the moment. I try to solve some issues with the deserialization in the JMSSerializerBundle. Therefore i need those methods. Never heard about Reflection before, and needed something to read about it. In that Moment i saw the tweet about this blogpost.
It helped me a lot. Now i only need some help with classes, where the only assessor is the constructor.
Like
class exampleClass{
private $name;
public functions __construct( $name){
$this->name=$name;
}
}
Hi Maximilian,
thanks for your comment 🙂
What kind of help you need with Classes? I will try to help 😉
I would not advice “injecting” params via constructor like this, it will cause dependency issue and is not testable. Hint: read about dependency injection
I won`t implement constructor injection (of parameters) as a usual case,
needed it only to make a given test green.
This example i gave is not that case that i am thinking of, only a simple example.
But i know about injection: it`s important to avoid dependency problems. And there i will inject classes instead of parameters. I am a big fan of the new podcast of @mathiasverraes and @everzet. It is awesome how they talk about modeling and DDD.
There is no specific problem i need to solve. I only questioned: How have they (the makers of the Bundle) made the setting of private properties, how do they set properties that normally goes through the constructor. But now i know it now. 🙂
If I am correct, this RFC was you was looking for https://wiki.php.net/rfc/propertygetsetsyntax-v1.2 sadly failed 🙁 .
Nice to see your implementation in Pure PHP.
Thank you.
Hi,
I just wanted to say I really don’t like this. Magically making all private properties public is something I would never use in production code. I know you said you can make them private again by creating some other method with specific name, but that is not a good solution. The reason the properties are marked private is because they are not supposed to be accessed directly. If you want to allow direct access, make the properties public. I really don’t understand the need for declaring properties private and then coding around that restriction to magically make them public again. There are so many ways this could cause problems down the road especially in a project with many developers and long life time.
I do get the inspiration for this and the C# code you posted and I like the idea of it and how it simplifies the calling side. But the key point in that code is that is goes through the getter and setter methods, not access the field directly. This way you are in control what happens when getting and setting values. If you would like to achieve something similar for PHP I think you could modify your code so that it first checks if the property has a getter/setter method and calls it if it has one. If not, then check if it is marked public and get/set the value if it is. Then if the property is not public and it does not have a getter/setter, then throw an exception because it is not allowed to be modified from outside. This way you get all the benefits of getter and setter methods and you will also have the control in the class what is public and what private (without hacks).
Hi,
If you liked this article you might be interested in my Prototype project that aims to provide many features involving getters and setters and allows methods (including getters and setters) to be defined at runtime.
https://github.com/ICanBoogie/Prototype
These are some really crazy ideas that might work, but please bear in mind that reflection is really slow! And the same goes for magic methods. So in the end its twice as slow!
Magic methods are something that is only to be used when performance is not really an issue (like testing, PHPSpec uses this for example). And also as Cvuorinen pointed out you should not break the property-access model (unless you really need to, Serialization and such).
I prefer to use public properties when it makes sense to do so, but Doctrine 2 won’t allow it, so I’ve had to do something very similar to what you’ve outlined here. With regard to your note about the disadvantage (“When using a full-blown IDE like PHPStorm, you will NOT see those class fields in auto-completion.”), one tip that someone pointed out to me on my similar blog post (http://russellscottwalker.blogspot.co.uk/2013/09/public-properties-getters-and-setters.html) is that you can use the @property (or @property-read or @property-write) phpDoc tags to expose the members to your IDE. Which is cool.
I’m a bit curious why you didn’t use the __call() magic method for the possible get/set* methods and what the performance hit is by using Reflection when accessing any runtime defined field.
Furthermore, although it has nothing to do with your implementation, but more the design area in particular: There are good cases where you want access to fields, but those should be fairly rare and in most cases it probably does more than just return a class field. The whole concept of an anemic domain model is frequently the smell of poor OO design. While I don’t necessarily agree on all points Fowler has to say on this topic, I wouldn’t necessarily advocate the use of getters and setters.
Thanks for reading.