While reading PHP documentation, especially the OOP chapter, I’ve discovered a few functions I didn’t know of, even if I use a lot PHP in my daily job. Please note that PHP5 was introduced in 2004, and these methods may evolve.

__autoload

When calling a class (or an interface) still not declared, PHP will call the __autoload function, if it was declared sooner. It can be usefull to reduce the number of require/include calls and parsing PHP files only on demand.

Simple example:

<?php // Objet.class.php
class Objet
{
};
<?php // test.php
function __autoload($class_name)
{
    echo "Autoloading class $class_name\n";
    $class_file = $class_name . '.class.php';
    if(FALSE === file_exists($class_file))
    {
        throw new Exception('Class "' . $class_name . '" could not be autoloaded (file missing)');
    }
    require_once $class_name . '.class.php';
    if(FALSE === class_exists($class_name))
    {
        throw new Exception('Class "' . $class_name . '" could not be autoloaded (not in file)');
    }
    echo "Autoloading done!";
    return true;
}

// Using "Object" class defined in Object.class.php
$obj = new Objet;

// Trying to use "ObjetNonDefini" will go in error:
$obj2 = new ObjetNonDefini;
$ php test.php
Autoloading class Objet
Autoloading done!
Autoloading class ObjetNonDefini
PHP Fatal error:  Uncaught exception 'Exception' with message 'Class "ObjetNonDefini" could not be autoloaded (file missing)' in /home/mycroft/tmp/php/test.php:9
Stack trace:
#0 /home/mycroft/tmp/php/test.php(26): __autoload('ObjetNonDefini')
#1 {main}
  thrown in /home/mycroft/tmp/php/test.php on line 9

__construct / __destruct

Like other OOP languages, PHP provides generic constructors/destructors that will be called on object instantiation and destruction. Note that destructor will be called even if object is not explicitaly destroyed (example: at the end of a script).

<?php // Objet.class.php
class Objet
{
    public function __construct()
    {
        echo "Constructor\n";
    }

    public function __destruct()
    {
        echo "Destructor\n";
    }
};
<?php // test.php
require_once("Objet.class.php");
$obj = new Objet;
echo "Fin du script.\n";
$ php test.php
Constructor
Fin du script.
Destructor

Visibility of private methods

PHP also manages private methods and variables. They are only accessible in their own instanciated object. But PHP allows to call a private method from an object instance from another object, as long as this object is from the same type. This is fully described in the OOP Visibility.

Example:

<?php // Objet.class.php
class Objet
{
    private $obj_name = NULL;

    public function __construct($name = NULL)
    {
        $this->obj_name = $name;
    }

    // Private method
    private function privateMethod()
    {
        echo "Methode privée dans " . $this->obj_name . "\n";
    }

    // This method will allow foreign objects to call our private method.
    public function test(Objet $t)
    {
        $t->privateMethod();
    }
};
<?php // fichier test.php
require_once("Objet.class.php");
$obj = new Objet('objet n°1');
$obj2 = new Objet('objet n°2');

// The "obj" object will call private method in obj2:
$obj->test($obj2);

And this works:

$ php test.php 
Methode privée dans objet n°2

__toString

The __toString function is a simple function allowing to define the class interacts when a String conversion of it is required (by using “print”).

    // Using the last object:
    public function __toString()
    {
        return "class " . $this->obj_name;
    }
// In test.php
echo $obj;
// Will show 'class objet n°1'

__invoke

In the same fashion, it is possible to define how the object will interact when being called as a function. This is done with the __invoke function

    // Using the last object:
    public function __invoke()
    {
        echo "Appel de echo sur " . $this . "\n";
    }
<?php // In test.php:
require_once("Objet.class.php");
$obj = new Objet('objet n°1');
$obj();

And when executing:

$ php test.php
Appel de echo sur class objet n°1

__get, __set, __isset, __unset

PHP allows affectation on any class instance any kind of values (like a hash table), as long as this is not a private variable:

<?php

class Objet {};
$obj = new Objet;
$obj->exemple = 1;
echo $obj->exemple . "\n"; // prints '1'

When affecting a variable this way, PHP will call the __set/__get functions. And because of this, it is possible, with reimplementing those functions, to define a new behavior:

<?php // Objet.class.php

class Objet
{
    private $data;
    public function __construct()
    {
        $data = array();
    }

    public function __set($name, $value)
    {
        echo "Setting $name to $value\n";
        $this->data[ $name ] = $value;
    }

    public function __get($name)
    {
        echo "returns $name\n";
        return $this->data[ $name ];
    }
};
<?php // In test.php

require_once("Objet.class.php");
$obj = new Objet;
$obj->priv = 1;
echo $obj->priv;

This example will return:

$ php test.php
Setting priv to 1
return priv
1

This also allows to protect the class contents. Note that if __set/__get is redefined, there won’t be anymore errors when trying to access private variables.

__call et __callStatic

As for variables, it is possible to catch undefined function (static or not) calls in classes, with using _call / __callStatic functions.

<?php // Objet.class.php
class Objet
{
    public function __call($func, $args)
    {
        echo "Calling $func\n";
    }

    public static function __callStatic($func, $args)
    {
        echo "Calling static $func\n";
    }
};
<?php // test.php

class Objet {};
$obj = new Objet;
$obj->exemple = 1; echo $obj->exemple . "\n";

At execution:

$ php test.php
Calling hello
Calling static hello

Those two functions, with the help of variable setters/getters, allow to entirely wrapper classes’ instances, allowing uses more interesting that simple inheritance.

__clone

__clone is called when asking for a copy of an object instance. This will result in 2 totally independant instances with the same content. While I’m not sure that clone is commonly used, __clone may be used to modify an object after cloning, or to not effectively clone the object ot use a singleton.

__sleep, __wakeup

Finally, __sleep/__wakeup are used when (un)serializing objects.

<?php // Objet.class.php

class Objet
{
    private $file_name = NULL;
    private $file_hd = NULL;

    public function __construct($file_name)
    {
        $this->file_name = $file_name;
        $this->file_open();
    }

    public function __destruct()
    {
        if($this->file_hd !== NULL)
            $this->file_close();
    }

    private function file_open()
    {
        echo "Opening file\n";
        $this->file_hd = fopen($this->file_name, "a+");
    }

    private function file_close()
    {
        if(NULL === $this->file_hd)
            return false;

        echo "Closing file\n";
        fclose($this->file_hd);
        $this->file_hd = NULL;
    }

    public function __sleep()
    {
        echo "* Serialization.\n";
        $this->file_close();

        return(array('file_name'));
    }

    public function __wakeup()
    {
        echo "* Unserialization.\n";
        $this->file_open();
    }
};

Et testons tout ça:

<?php // test.php

require_once("Objet.class.php");

$obj = new Objet('helloworld.txt');

$serializedObj = serialize($obj);
unset($obj);
var_dump($serializedObj);

$newObj = unserialize($serializedObj);

echo "Fin du script\n";

We’ll check the behavior:

$ php test.php 
Opening file
* Serialization.
Closing file
string(62) "O:5:"Objet":1:{s:16:"Objetfile_name";s:14:"helloworld.txt";}"
* Unserialization.
Opening file
Fin du script
Closing file

Also, see 9 magic methods for PHP.