There seems to be a lot of questions on setters and getters in PHP. However, none of them seem to mention that they do not work with public variables.
I have a series of public variables, which on setting need the same type of data checking (mainly strip_tags()).
What is the most code efficient way to do this whilst keeping the variables public?
The only option which seems to be available is creating a method 'setPropertyName' for all of my variables, which seems unnecessary to me.
Thanks for any help.
You can make them private, and using a public __set() and __get() to fetch the variables if they exists, and apply the validation/sanitation operations when they set.
For example:
class Foo {
private $variable;
private $otherVariable;
public function __get($key) {
return $this->$key;
}
public function __set($key, $value) {
$this->$key = strip_tags($value);
}
}
$foo = new Foo;
$foo->variable = "test"; //Works.
echo $foo->variable; //test
One thing you could try is the magic method __call($name,$args), then you wouldn't need to code the setPropertyName and getPropertyName functions:
function __call($name,$args){
$variable=lcfirst(substr($name,3));
if(!isset($this->$variable))
return false;
if(substr($name,0,3)=='set')
$this->$variable=$args[0];
else
return $this->$variable;
return true;
}
That being said, magic methods __get and __set work great with public variables if utilized properly. Below is how I utilize them:
public $variables=array();
function __get($name){
return isset($this->variables[$name])?$this->variables[$name]:false;
}
function __set($name,$value){
$this->variables[$name]=$value;
}
Then you can access them by using $this->name; rather than $this->getName();
Put both of them together and then you can do it however you want.
Again, this is a backbone. If you want to strip tags, you can put that in the code either in the setter or getter functions, or modify the call function to check for a 2nd argument that will strip the tags $this->setName($value,true);//strip tags
It is actually probably best practice to actually explicitly define your getters and setters. That being said you can use the __set() and __get() magic methods to provide common handling for requests to properties that are inaccessible from outside the class (protected and private).
So, all you would need to do is make your properties protected/private and specify __get() and __set() methods (also might need __isset() and __unset() as well if you will be checking the properties using isset() or trying to unset() properties).
Again, it is really best practice (IMO) to make all class properties inaccessible from outside the class and explicitly make setters/getters as need to provide access.
Related
I use magic methods _set, _get:
public function __set($name, $value)
{
array_push($this->groups, $value);
}
public function __get($name)
{
return $this->$name;
}
And use this like as:
// Set
$menu->groupName = 'Регистрация';
// Get
echo $menu->groupName
Why echo $menu->groupName does not work? it returns nothing. It should return text 'Регистрация'.
I tried just return in _get:
return $name;
In your __set you process assigning to nonexistent property as adding it's value to array $this->groups. This code does not create property for you.
When you want to access nonexistent property __get works. But in it you want to access groupName property, but you didn't create it.
To debug your code, add a line
echo'<pre>',print_r($this),'</pre>';
to you __get method:
public function __get($name)
{
echo'<pre>',print_r($this),'</pre>'; // TODO
return $this->groups[0];
}
You will see that "Регистрация" is there, but it is in $groups property.
So, you can either modify __get to
public function __get($name)
{
return $this->groups[0];
}
as you don't have other values in $groups.
Or modify full code:
public function __set($name, $value)
{
$this->groups[$name] = $value;
}
public function __get($name)
{
return isset($this->groups[$name]) ? $this->groups[$name] : 'NO VALUE';
}
From The PHP Documentation on overloading:
The overloading methods are invoked when interacting with properties or methods that have not been declared or are not visible in the current scope. The rest of this section will use the terms "inaccessible properties" and "inaccessible methods" to refer to this combination of declaration and visibility.
In short, the properties you want to be handled by your overloading method MUST be either private, protected, or undefined.
Moreover, overloading itself isn't commonly used within PHP. In most cases, it's better to create your own get() and set() methods, rather than inherit the complexities associated with the overloading magic methods. Even then, custom get/set methods are only practical if you are doing more than just storing the data.
Where Overloading Makes Sense:
Overloading is great for security, validation, and data transformation, because it allows you to control the visibility of information within your application.
With overloading you can create variables that:
Can only be read
Can only be written to
Can only be read or written to a certain number of times
Can be validated before writing
Can update other variables
Etc.
On Zend Quick Start Guide here http://framework.zend.com/manual/en/learning.quickstart.create-model.html we can see:
class Application_Model_Guestbook
{
protected $_comment;
protected $_created;
protected $_email;
protected $_id;
public function __set($name, $value);
public function __get($name);
public function setComment($text);
public function getComment();
...
I normally create my getters and setters without any magic method. I've seen this on the quick guide, and I don't understand why may we need this.
Can anyone help me out?
Thanks a lot
You (usually) never call __set or __get directly. $foo->bar will call $foo->__get('bar') automatically if bar is not visible and __get exists.
In the tutorial you've linked to, the getter and setter get set up to automatically call the appropriate individual get/set functions. So $foo->comment = 'bar' will indirectly call $foo->setComment('bar'). This isn't necessary... it's only a convenience.
In other cases, __get can be useful to create what looks like a read-only variable.
If you "make your own" getters and setters, you'll be making two functions for each property: getPropname() and setPropname. By using PHP's "magic method" setter/getter, you don't write individual methods for each property. You can set/get properties as if they were public. Within the overload functions, you add the logic specific to each property. Example:
public function __set($name, $value) {
switch ($name) {
case 'comments':
// do stuff to set comments
break;
case 'parent_user':
// do stuff to set parent user
break;
}
}
public function __get($name) {
switch ($name) {
case 'comments':
// do stuff to get comments
break;
case 'parent_user':
// do stuff to get parent user
break;
}
}
Now I can access comments by using $obj->comments to either set or get.
To achieve the above functionality without using the overloads, I would have had to write 4 different methods instead. This is really more about code organization, both in terms of the actual file and in terms of creating a standardized interface for objects within a project.
I personally prefer to do as you do and write separate methods for each property that I need a complex getter/setter. To me, it is more clearly organized, and there is a clear separation between "simple" properties of an object and those properties which have greater complexity or one-to-many relationships.
The __get and __set magic methods exist for TWO reasons:
So that you don't have to spend time creating vanilla accessor methods for all of your properties.
To allow you to implement property overloading.
If you have properties that need special treatment, then the magic methods are not for you. However, if your properties simply contain data and there are no dependencies then there's no reason NOT to use the magic methods.
Further on the tutorial it gets you to modify the __get() and __set() methods so you'll see why they're there.
Having magic handling like that can allow you to do some neat stuff like even making "read only" properties and can prevent you from bloating your class with a messy load of getter/setters.
You'll run into problems when you've used __set and want to override the setter functionality in a child class. You'll have to copy the entire code in __set and change only the specific part instead of just simply overwrite one specific setter function -> redundant code
This problem can be avoided by calling the specific setter in __set (thanks to cHao for the tip).
Example:
class Foo1 {
protected $normal;
protected $special;
public function setSpecial($special) {
if ($special == isReallySpecial()) {
$this->special = $special;
}
}
public function __set($key, $value) {
switch ($key) {
case 'normal':
$this->normal = $value;
break;
case 'special':
$this->setSpecial($value);
}
}
}
class Foo2 extends Foo1 {
public function setSpecial($special) {
if ($special == isNotReallySpecial()) {
$this->special = $special;
}
}
}
Summary
Code sample:
Class People {
// private property.
private $name;
// other methods not shown for simplicity.
}
Straight forward. Let me assume that $name is a PRIVATE class member (or property, variable, field, call it as you wish). Is there any way to do these in PHP:
$someone = new People();
$someone->name = $value;
$somevar = $someone->name;
WITHOUT using __get($name) and __set($name, $value).
Background
I needed to check the assigned $value, therefore I simply need a getter setter like this:
getName();
setName($value);
And NOT necessarily a getter setter magic method overloading like this:
__get($value);
__set($value, $name);
That said, I simply need a getter setter. But that's NOT what I want. It just doesn't feel like object oriented, for people from static typed language such as C++ or C# might feel the same way as I do.
Is there any way to get and set a private property in PHP as in C# without using getter setter magic method overloading?
Update
Why Not Magic Method?
There are rumors floating around the web that magic method is 10x slower then explicit getter setter method, I haven't tested it yet, but it's a good thing to keep in mind. (Figured out that it's not that slow, just 2x slower, see the benchmark result below)
I have to stuff everything in one huge method if I use magic method rather then split them into different function for each property as in explicit getter setter. (This requirement might have been answered by ircmaxell)
Performance Overhead Benchmarking
I'm curious about performance overhead between using magic method and explicit getter setter, therefore I created my own benchmark for both method and hopefully it can be useful to anyone read this.
With magic method and method_exist:
(click here to see the code)
Getter costs 0.0004730224609375 second.
Setter costs 0.00014305114746094 second.
With explicit getter setter:
(click here to see the code)
Getter costs 0.00020718574523926 second.
Setter costs 7.9870223999023E-5 second (that's 0.00007xxx).
That said, both setter and getter with magic method and method exists justs costs 2x than the explicit getter setter. I think it's still acceptable to use it for a small and medium scale system.
Nope.
However what's wrong with using __get and __set that act as dynamic proxies to getName() and setName($val) respectively? Something like:
public function __get($name) {
if (method_exists($this, 'get'.$name)) {
$method = 'get' . $name;
return $this->$method();
} else {
throw new OutOfBoundsException('Member is not gettable');
}
}
That way you're not stuffing everything into one monster method, but you still can use $foo->bar = 'baz'; syntax with private/protected member variables...
ReflectionClass is your salvation
I know it's too late for Hendra but i'm sure it will be helpfull for many others.
In PHP core we have a class named ReflectionClass wich can manipulate everything in an object scope including visibility of properties and methods.
It is in my opinion one of the best classes ever in PHP.
Let me show an example:
If you have an object with a private property and u want to modify it from outside
$reflection = new ReflectionClass($objectOfYourClass);
$prop = $reflection->getProperty("PrivatePropertyName");
$prop->setAccessible(true);
$prop->setValue($objectOfYourClass, "SOME VALUE");
$varFoo = $prop->getValue();
This same thing you can do with methods eighter;
I hope i could help;
If using magical properties doesn't seem right then, as already pointed out by other posters, you can also consider ReflectionClass::getProperty and ReflectionProperty::setAccessible.
Or implement the necessary getter and setter methods on the class itself.
In response to the language features issue that you raised, I'd say that having a dynamically typed language differ from a statically typed one is expected. Every programming language that has OOP implements it somewhat differently: Object-Oriented Languages: A Comparison.
class conf_server
{
private $m_servidor="localhost";
private $m_usuario = "luis";
private $m_contrasena = "luis";
private $m_basededatos = "database";
public function getServer(){
return $this->m_servidor;
}
public function setServer($server){
$this->m_servidor=$server;
}
public function getUsuario(){
return $this->m_usuario;
}
public function setUsuario($user){
$this->m_usuario=$user;
}
public function getContrasena(){
return $this->m_contrasena;
}
public function setContrasena($password){
$this->m_contrasena=$password;
}
public function getBaseDatos(){
return $this->m_basededatos;
}
public function setBaseDatos($database){
$this->m_basededatos->$database;
}
}
PHP has _get and _set functions built in. Is it better to write my own get and set functions for each variable or use the built in functions with a ton of if else if? What are the pros and cons of each method?
__get and __set are magic methods that should usually be used to solve difficult problems rather than to be used as a design basis.
For instance, I found myself on a project where I had to analyze a site that used OOP with deep inheritance (> 2) and one of the important base classes had a public property called name. However, it also had getters and setters (getName, setName) that accessed that property for the mere purpose of getting and setting it. Many classes called getName and just as many accessed the name property directly! Not great design.
The magic methods allowed me to solve the problem by renaming the property to _name and making it private, forcing all requests to the property through the getters and setters.
This being said, there's no need for getters and setters if you're just treating a property like a variable. In that case, just make the property public!
In your case, since there is validating/sanitizing going on, you should employ getters and setters and code them directly as methods (rather than unnecessarily incurring the overhead from the magic methods).
Here is how I handle this problem.
final public function __set($key, $value) {
$method = 'set' . ucfirst($key);
if (method_exists($this, $method)) {
$this->data[$key] = $this->$method($value);
} else {
$this->data[$key] = $value;
}
}
final public function __get($key) {
$method = 'get' . ucfirst($key);
if (method_exists($this, $method)) {
return $this->$method($this->data[$key]);
} else {
return $this->data[$key];
}
}
If you have a custom handler for a property, it gets called (assuming it's named getProperty). Otherwise, the default get/set magic method is used.
I tend to go by the rule that if you have complex get or set logic then add a separate get or set method. If you're doing something simple you can leverage __get or __set when you would otherwise repeat yourself in a lot of custom get/set methods.
What are getters and setters in PHP5?
Can someone give me a good example with an explanation?
This is concept for data hiding (or encapsulation) in OOP. For example if you want to have a certain property in your class let's say 'Amount' and give the client of you class the option to change or extract its value You should make your variable 'Amount' private (not visible for those who use your class) and generate two methods a getter and a setter that manipulates your value (that are public).
The reason is to be able to validate data or manipulate it before setting or getting your value. Here is a brief example:
class test {
private $count; //those who use your class are not able to see this property, only the methods above
public function setCount( $value )
{
//make some validation or manipulation on data here, if needed
$this->count = $value;
}
public function getCount()
{
return $this->count;
}
}
Attributes of classes can be private. That means only the object can read and write its own private attributes. Therefore you need methods to do that. The methods that read and return an attribute value are called getters and those that write attributes are called setters. With these methods the classes can control what’s going out and what’s coming in. This concept is called encapsulation.
Getters and Setters are quite new concept in PHP 5 in the form of two magical functions __get() and set(). These two functions set or get property value of an object dramatically as explained in the following example.
class Datatype{
private $thing;
public function _set($k,$v){
$this->$k = $v;
}
public function __get($k){
return $this->$k;
}
}
The PHP manual is really not very verbose on the issue, but there is a very detailed example that should explain a lot. Magic methods: Property overloading