Отправляет email-рассылки с помощью сервиса Sendsay

PHP 5 для начинающих

  Все выпуски  

Магические методы


PHP 5 для начинающих

В PHP существует ряд методов и функций с названиями, начинающимися с двух знаков подчеркивания. Все они, если определены, исполняются автоматически при наступлении определенного события и не рассчитаны на прямой вызов. Например, ранее рассмотренные методы __construct() и __destruct() исполняются при создании и разрушении объекта (см. Глава 7, Конструктор и деструктор), а метод __clone() - при клонировании объекта (см. «Клонирование»). Благодаря такому особому поведению эти методы получили название магических.

[Внимание]Внимание

Строго говоря, PHP резервирует для магических методов все названия, начинающиеся с двух знаков подчеркивания, поэтому использовать подобные названия для своих собственных методов и функций не рекомендуется.

Помимо уже изученных, существуют и другие магические методы, рассмотрением которых мы сейчас и займемся.

В данном руководстве все учебные примера с целью большей простоты представлены таким образом, будто бы все используемые в них классы и код находятся в одном и том же файле. В реальных приложениях, однако, принято каждый класс размещать в отдельном файле. Следовательно, скрипт, использующий тот или иной класс, должен сперва включить файл с определением данного класса.

[Подсказка]Подсказка

Для включения файлов с определениями классов лучше всего пользоваться выражением require_once. Оно позволяет, с одной стороны, на самом раннем этапе выявить проблемы, сввязанные с невозможностью включить нужный файл, а, с другой, избежать повторного включения одного и того же файла.

В сложных приложениях с большим количеством классов контроль за включением всех необходимых файлов становится трудоемким, списки включаемых файлов в начале каждого скрипта - слишком длинными, а надежность приложения снижается за счет повышения вероятности ошибок. В PHP 5 избавиться от необходимости такого контроля можно с помощью автоматической загрузки объектов посредством магической функции __autoload().

[Замечание]Замечание

Обратите, пожалуйста, внимание, что это именно функция, а не метод.

Функция __autoload() вызывается автоматически при попытке использования класса, который еще не был определен. Она получает в качестве аргумента название этого класса, что позволяет включить нужный файл в самой этой функции, избежав, таким образом, фатальной ошибки.

[Подсказка]Подсказка

При использовании автозагрузки необходимо следовать тем или иным соглашениям о названиях файлов с определениями классов. Обычно названия файлов совпадают с названиями классов (класс Foo находится в файле Foo.php, класс Bar - в файле Bar.php и т. д.).

PHP 5 поддерживает своеобразную перегрузку (overloading) отсутствующих свойств и методов класса. При попытке вызова отсутствующего метода или доступа к отсутствующему свойству автоматически вызывается соответствующий магический метод (если, конечно, он определен для данного класса).

[Внимание]Внимание

Объявления магических методов должны быть публичными. Кроме того, они не могут быть объявлены статическими.

Метод __call(). Исполняется при попытке вызова несуществующего метода. Принимает в качестве аргументов название вызванного метода и массив переданных ему параметров. Возвращаемая величина будет передана в точку вызова.

<?php

class Foo
{
    public function __call($method, $args)
    {
        print "The $method method does not exist.";
        return false;
    }
}

?>
        
<?php

$foo = new Foo;
$bar = $foo->bar();
var_dump($bar)

?>
        
The bar method does not exist.
bool(false)
        

Метод __set(). Исполняется при попытке установить значение несуществующего свойства. Принимает в качестве аргументов название этого свойства и требуемое значение.

<?php

class Foo
{
    public function __set($var, $value)
    {
        print "The $var property does not exist.";
    }
}

?>
        
<?php

$foo = new Foo;
$foo->bar = 'Bar';

?>
        
The bar property does not exist.

Метод __get(). Исполняется при попытке получить значение несуществующего свойства. Принимает в качестве аргумента название этого свойства.

<?php

class Foo
{
    public function __get($var)
    {
        print "The $var property does not exist.";
        return null;
    }
}

?>
        
<?php

$foo = new Foo;
$bar = $foo->bar;

?>
        
The bar property does not exist.

Метод __isset(). Исполняется при попытке выяснить, установлено ли значение несуществующего свойства (т. е., при вызове функции isset()). Принимает в качестве аргумента название этого свойства.

[Замечание]Замечание

Поддерживается, начиная с версии PHP 5.1.0.

<?php

class Foo
{
    public function __isset($var)
    {
        print "The $var property does not exist.";
        return false;
    }
}

?>
        
<?php

$foo = new Foo;
if (isset($foo->bar)) {
    /* ... */
}

?>
        
The bar property does not exist.

Метод __unset(). Исполняется при попытке установить значение несуществующего свойства в null (т. е., при вызове функции unset()). Принимает в качестве аргумента название этого свойства.

[Замечание]Замечание

Поддерживается, начиная с версии PHP 5.1.0.

<?php

class Foo
{
    public function __unset($var)
    {
        print "The $var property does not exist.";
    }
}

?>
        
<?php

$foo = new Foo;
unset($foo->bar);

?>
        
The bar property does not exist.

Метод __sleep(). Исполняется при вызове функции serialize(), которая преобразует данные в пригодный для сохранения вид. Может быть использован, например, для упрощения сохраняемого объекта перед сохранением (удаления несущественных или вычисляемых из других данных). Возвращает массив, содержащий названия всех свойств объекта, которые подлежат сохранению.

Метод __wakeup(). Исполняется при вызове функции unserialize(), которая используется для восстановления ранее сохраненных данных.

Метод __toString(). Исполняется при преобразовании объекта к строковому типу (например, при выводе его с помощью print или echo). Должен возвращать строковое значение.

<?php

class Foo
{
    public function __toString()
    {
        return 'Hi from Class ' . __CLASS__;
    }
}

?
        
<?php

$foo = new Foo;
print $foo;

?>
        
Hi from Class Foo
[Замечание]Замечание

Сравните со стандартным поведением объектов в данной ситуации.

print new stdClass;
Object
id #1

Метод __set_state(). В отличие от других магических методов, является статическим. Используется при экспорте классов с помощью функции var_export(). Принимает в качестве аргумента ассоциативный массив с экспортируемыми свойствами.

[Замечание]Замечание

Поддерживается, начиная с версии PHP 5.1.0.

var_export(new stdClass);
stdClass::__set_state(array(
))        
<?php

class Foo
{
    public $bar;

    public static function __set_state($properties)
    {
        $obj = new Foo;
        $obj->bar = strtolower($properties['bar']);
        return $obj;
    }
}

?>
        
<?php

$foo = new Foo;
$foo->bar = 'Bar';
eval('$o = ' . var_export($foo, true) . ';'); 1
var_dump($o);

?>
        
1
$o = Foo::__set_state(array( 'bar' => 'Bar', ));
object(Foo)#2 (1) {
  ["bar"]=>
  string(3) "bar"
}
        
  1. Разработайте функцию автозагрузки для случая, когда названия классов и файлов отражают их положение в хранилище включаемых файлов следующим образом: класс Foo определен в файле Foo.php, класс Foo_Bar - в файле Foo/Bar.php, класс Foo_Bar_Class - в файле Foo/Bar/Class.php и т. д. Предполагается, что путь к самому хранилищу уже включен в поиск для включаемых файлов.

    [Подсказка]Подсказка

    Для трансляции названий классов в пути и названия файлов можно воспользоваться функцией strtr().

    print strtr("strtr_demo", '_', ' ');
    strtr demo

    Для обеспечения платформенной независимости можно воспользоваться предопределенной константой DIRECTORY_SEPARATOR (разные операционные системы используют различный разделитель директорий, например, Windows - \, Linux - /).

  2. Упростите следующий код.

    <?php
    
    class Foo
    {
        public function __get($var)
        {
            return isset($this->$var) ? $this->$var : null;
        }
    }
    
    ?>
                    
  3. Вы занимаетесь отладкой класса Foo и для контроля состояния объектов этого класса используете функцию var_dump(). Однако, прибегать к ней приходится достаточно часто и Вам бы хотелось упростить процесс контроля, например, получив возможность пользоваться более привычными выражениями print или echo. Предложите способ достичь желаемой цели.

«Ответы и решения к Глава 12, Магические методы»

Created with DocBook


В избранное