OOP – Magic Methods in PHP
In PHP, there is a group of methods called magic methods that can assist when an event occurs on the object. These methods are invoked without needing to be explicitly called by you, which is why they are referred to as magic methods.
Most likely, you are familiar with two of these if you have used another programming language: the constructor and the destructor of the object.
Métodos mágicos
construct destruct call y callstatic getvalue setvalue isset unset | serialize, sleep unserialize, wakeap tostring invoke setstate clone debuginfo |
This time, to indicate visibility or access levels, we will use the following notation:
public
protected
private
Construct
Probably, the __construct()
method is the most well-known in the entire list, and it’s the method you first learn when studying object-oriented programming in PHP.
<?php class Perro{ public $nome; public $raza; public __construct(string $n,string $r){ $this->nombre = $n; $this->raza = $r; } } $p = new Perro("Yoshi","Terrier"); echo $p->nombre;//deberia darnos Yoshi
This a very simple example but functional
Destructor
The __destruct()
method is called when the object is destroyed. I’m not very good at giving examples, and the ones I found online weren’t good enough. So, imagine it’s like an online browser game, and you have an object, for example, a sword.
class espada{ __destruct(){ echo "la espada se ha roto"; } }
Call y CallStatic
The __call()
and __callStatic()
methods are invoked when you try to call a method that doesn’t exist or is inaccessible (private or protected) in an object. The __callStatic()
method is triggered when trying to call a static method and must be declared as static.
<?php class Perro{ private $raza; private $nombre; public function __construct($nombre,$raza){ $this->raza = $raza; $this->nombre = $nombre; } private function ladrar(){ echo "waw waw"; } public function __get($property_name){ return $this->$property_name; } public function __call($method_name,$args){ if(method_exists($this,$method_name)){ echo "el metodo es privado"; } else{ echo "<p>tal metodo no existe en el objeto de clase ".__CLASS__."</p>"; } } } $p = new Perro("Yoshi","Terrier"); echo $p->__get('nombre');//obtendra Yoshi $p->ladrar(); $p->nadar();
class SampleClass { public function __call($name, $args) { if ($name == 'multiply') { if (count($args) == 2) { return $args[0] * $args[1]; } else if (count($args) == 3) { return $args[0] * $args[1] * $args[2]; } } // Handle other methods or throw an error if the method is not defined } } $obj = new SampleClass(); echo $obj->multiply(2, 3)."\n"; // Output: 6 echo $obj->multiply(2, 3, 4); // Output: 24
Get value
__get() – It is used to read inaccessible data (protected, private, or non-existent properties).
__get() example<?php class Perro{ private $raza; private $nombre; public function __construct($nombre,$raza){ $this->raza = $raza; $this->nombre = $nombre; } public function __get($property_name){ return $this->$property_name; } } $p = new Perro("Yoshi","Terrier"); echo $p->__get('nombre');//obtendra Yoshi
Set value
The real way to assign a value to an inaccessible (private or protected) property of an object is by using __set().
__set() example<?php class Perro{ private $raza; private $nombre; public function __construct($nombre,$raza){ $this->raza = $raza; $this->nombre = $nombre; } public function __get($property_name){ return $this->$property_name; } public function __set($property_name,$property_value){ $this->$property_name = $property_value; } } $p = new Perro("Yoshi","Terrier"); $p->__set('nombre','Joker'); echo $p->__get('nombre');//obtendra Joker
isset
It is executed when isset()
is called on an inaccessible or non-existing property: __isset()
.
<?php class Perro{ private $raza; private $nombre= "yoshi"; public function __isset($r){ if(isset($this->$r)){ echo "la propiedad existe \n"; }else{ echo "no hay ninguna propiedad $r iicializada \n"; } } } $p = new Perro(); $p->__isset("nombre"); $p->__isset("raza");
unset(__unset())
It is executed when unset
is called on a private (private
), protected
, or non-existent property.
<?php class Perro{ private $raza= "buldog"; private $nombre= "yoshi"; public function __unset($n){ if(isset($this->$n)){ unset($this->$n); } } } $p = new Perro(); $p->__unset("raza"); var_dump($p);
As you can see, we have destroyed the $raza property of the object.
Use case, I would say that this method makes more sense to be used when the property is an associative array and we want to remove one of its members. The use we gave it in the example wouldn’t make much sense, since we created that variable for a reason in the first place, or I don’t see the point at this moment, although it makes it easier to see the functionality of the method in this example.
Serialize(__serialize(), __sleep())
In case an object has the __serialize()
or __sleep()
method, it is executed before serialization.
In this method, we must return an array with the names of all the variables of the object that will be serialized.
public function __sleep ( void ) : array{ //code //must return an associative array }
__serialize()
public function __serialize ( void ) : array{ //code //must return an associative array }
Probablemente __serialize()
remplace a __sleep()
en un futuro
Generally, when we use serialize
in an object, the result is as follows:
<?php class Perro{ private $raza= "buldog"; private $nombre= "yoshi"; } $p = new Perro(); $x= serialize($p); var_dump($x);
string(81) "O:5:"Perro":2:{s:11:"Perroraza";s:6:"buldog";s:13:"Perronombre";s:5:"yoshi";}"
As you might be thinking, but what is this perroraza, of course, this is not what we want when serializing an object.
<?php class Perro{ private $raza= "buldog"; private $nombre= "yoshi"; public function __serialize(): array{ return ["raza","nombre"]; } } $p = new Perro(); $x = serialize($p); var_dump($x);
string(48) "O:5:"Perro":2:{i:0;s:4:"raza";i:1;s:6:"nombre";}"
If we run unserialize
, we will get the following; this matter of serializing and deserializing is starting to get interesting
var_dump(unserialize($x));
object(Perro)#2 (4) { ["raza":"Perro":private]=> string(6) "buldog" ["nombre":"Perro":private]=> string(5) "yoshi" ["0"]=> string(4) "raza" ["1"]=> string(6) "nombre" }
To understand more about the topic of serialize and unserialize
, I recommend reading this topic.
unserialize (__unserialize() y __wakeup())
Each time an unserialize
is called on the object, it will execute; if the __unserialize
and __wakeup
methods are declared, __unserialize
will execute instead of __wakeup
.
This method can reconstruct any resources that the object may have.
The intended use for __wakeup()
is to reestablish database connections that may have been lost during serialization and to perform other reinitialization tasks.
__wakeup().
disponible desde PHP 7.4.0__unserialize()
toString (__toString)
This method is executed each time our object is attempted to be used as a string.
__toString example<?php class Perro{ private $raza= "buldog"; private $nombre= "yoshi"; public function __toString(){ echo "raza:".$this->raza."\n nombre:".$this->nombre; } } $p = new Perro(); $p->__toString();
Another example to clarify the concept:
Ejemplo 2 de __toString<?php class Perro{ private $raza= "buldog"; private $nombre= "yoshi"; public function __toString(){ return "raza:".$this->raza."\n nombre:".$this->nombre; } } $p = new Perro(); echo "".$p;
Invocation
__invoke() is called when an object is attempted to be used as a function.
__invoke() example<?php class Perro{ private $debug=false; private $raza= "buldog"; private $nombre= "yoshi"; private function ladrar(){ echo "waw waw"; } public function __invoke(){ echo "raza: $this->raza - nombre: $this->nombre"; } } $p = new Perro(); $p();
Set state
The __set_state
method is a static method that is called when an object is exported with the var_export()
function. This function returns a parsable string representation of a variable, and when it encounters an object, it uses the __set_state
method to recreate the object from its exported state.
sintaxis
Sintaxis / Sintaxpublic static function __set_state ( array $properties ) : object{ //code //must return return object }
Clone
It is executed once the object has been cloned; if the __clone() method is defined, it will be called, allowing any property that needs to be changed to be modified.
<?php class Perro{ private $raza; private $nombre; public function __construct($nombre,$raza){ $this->raza = $raza; $this->nombre = $nombre; } private function ladrar(){ echo "waw waw"; } public function __get($property_name){ return $this->$property_name."\n"; } public function __set($property_name, $value){ $this->$property_name = $value; } public function __clone(){ $this->nombre =""; } public function __call($method_name,$args){ if(method_exists($this,$method_name)){ echo "el metodo es privado \n"; } else{ echo "tal metodo no existe en el objeto de clase ".__CLASS__."\n"; } } } $p = new Perro("Yoshi","Terrier"); echo $p->__get('nombre');//obtendra Yoshi $p->ladrar(); $p->nadar(); $p2 = clone $p; echo $p2->__get('nombre'); echo $p2->__get('raza'); echo $p2->__set('nombre','pako'); echo $p2->__get('nombre'); echo $p->__get('nombre'); unset($p); echo $p2->__get("nombre");
The above is a simple example, but it makes it clear what can be done with __clone()
debuginfo
Finally, we have the __debugInfo() method, which is invoked by var_dump().
Sintaxis / Sintaxpublic function __debugInfo ( void ) : array{ //code //must return an array }
As you can see, the method must return an array.
If the method is not defined on an object, all public, protected, and private properties will be displayed.
class Perro{ private $debug=false; private $raza= "buldog"; private $nombre= "yoshi"; private function ladrar(){ echo "waw waw"; } public function __debuginfo(){ if($this->debug){ $data["properties"]="raza,nombre"; return $data; } else{ return array(get_object_vars ($this),get_class_methods($this)); } } } $p = new Perro(); var_dump($p);