#7. 8 php ООП Перехват обращений к членам класса

При обращении к несуществующим или недоступным из данной части программы свойствам и методам класса, имеется возможность перехватить такие обращения и выполнить какие-то действия. Для этого предназначены специальные методы, которые должны быть реализованы в классе:

  • Метод __get вызывается каждый раз, когда мы пытаемся обратиться к несуществующему или недоступному свойству для его чтения, и принимает в качестве аргумента имя этого свойства. Например, при попытке получить и вывести на экран значение private-свойства property:
    <?php
    class Example
    {
        private $property;
    
        public function __get($name)
        {
            echo "Свойство объекта '$name' не существует или не доступно для чтения";
        }
    }
    
    obj = new Example;
    echo obj->property;

    будет выведено сообщение:

    Свойство объекта 'property' не существует или не доступно для чтения

  • Метод __set вызывается при установке значения несуществующего или недоступного свойства и принимает в качестве аргумента имя свойства $name и значение $value:
    <?php
    class Example
    {
        private $property;
    
        public function __set($name, $value)
        {
            echo "Свойство объекта '$name' не существует или не доступно для записи";
        }
    }
    
    $obj = new Example;
    $obj->property = 10;

    Так как мы попытались установить значение недоступного свойства property, то в результате выполнения последней строки будет вызван метод __set, который выведет соответствующее сообщение:

    Свойство объекта 'property' не существует или не доступно для записи

  • Наконец, метод __call вызывается при обращении к несуществующему/недоступному методу. Он получает на вход имя вызываемого метода и список передаваемых параметров:
    <?php
    class Example
    {
        private $property;
    
        public function __call($name, $args)
        {
            echo "Метод '$name' не существует или не доступен";
        }
    }
    
    $obj = new Example;
    $obj->set_property(10);
    

    Результатом выполнения примера будет сообщение о том, что метод "set_property" не существует или не доступен.

Описанные выше методы используются для динамического создания свойств и методов класса. В примере 1 для хранения динамически созданных свойств объекта $lion используется ассоциативный массив $vars.

Пример 1. Динамические свойства

<?php
class Animal
{
    private $name;
    private $vars;
   
    public function __construct($text)
    {
        $this->name = $text;
        $this->vars = [];
    }
 
    public function __get($name)
    {
        echo "Перехват: чтение значения свойства '$name'<BR>";
        return isset($this->vars[$name]) ? $this->vars[$name] : null;
    }
 
    public function __set($name, $value)
    {
        echo "Перехват: установка значения свойства '$name' в значение '$value'<BR>";
        return $this->vars[$name] = $value;
    }
 
    public function __call($name, $args)
    {
        echo "Перехват вызова незарегистрированного метода '$name'<BR>";
    }
   
    public function get_name()
    { 
        return $this->name;
    }
 
}
 
$lion = new Animal("Бонифаций");
$lion->age = 5;
$lion->name = "Симба";
echo $lion->age, "<BR>";
echo $lion->name, "<BR>";
echo "Используем 'get_name()' для получения имени<BR>";
echo $lion->get_name(), "<BR>";
echo $lion->get_age();

При установке несуществующего свойства age:

$lion->age = 5;

соответствующий элемент добавляется в массив $vars, и его значение мы получаем далее при чтении свойства age:

echo $lion->age;

При попытке установки значения свойства $name:

$lion->name = "Симба";

объявленного как private, добавляется элемент массива $vars с одноименным индексом "name", значение которого мы и получим, обратившить к свойству name объекта $lion напрямую для чтения:

echo $lion->name;

Если же мы используем метод get_name, описанный в классе, для получения имени, то получим значение private-свойства name.

Обратившись к несуществующему методу объекта:

$lion->get_age()

получим сообщение о том, что произошел перехват данного вызова.

Результат выполнения примера:



Рис. 1. Динамическое создание свойств

Замечание: Динамическое создание свойств по умолчанию

Если в классе не будет описан метод __set, то по умолчанию при попытке присвоить значение несуществующему свойству объекта PHP автоматически создаст соответствующее свойство. Например, в результате выполнения кода,

$lion = new Animal("Бонифаций");
$lion->age = 5;
echo "Льву по имени ", $lion->get_name(), " ", $lion->age, " лет<BR>";

даже если методы __set и __get не описаны, получим строку:

Льву по имени Бонифаций 5 лет.

Однако, начиная с PHP 8.2.0, такой подход считается устаревшим, и для работы с произвольными именами свойств класс должен реализовать описанные выше специальные методы. Если все же предполагается использование динамических свойств, то класс нужно пометить атрибутом AllowDynamicProperties

Key Words for FKN + antitotal forum (CS VSU):