Март 05 2008
Перехват обращения к несуществующим свойствам объектов в PHP5
В строгих языках программирования типа C++ и Java программист обязан явно определять какими свойствами обладает тот или иной класс, причем явно указывая их области видимости (public, protected или private). В PHP4 такой строгости не было и в некоторых случаях это приводило к ошибкам, которые достаточно трудно отловить.
В PHP5 у свойств классов появились области видимости и все стало более-менее строго. Обращение к несуществующему статическому свойству класса
<?php
class A { }
A::$myVar = 'test';
?>
приводит к фатальной ошибке: “Fatal error: Access to undeclared static property: A::$myVar in C:\test.php on line 7″. Однако, для совместимости с PHP4 при обращении к свойству объекта никаких ошибок не генерируется. В PHP4 вы могли расширить объект, добавив в него новые свойства прямо в runtime вот так:
<?php
class A {
}
$a = new A();
$a->MyVar = 'test';
?>
Разумеется, делать так ни в коем случае не нужно ни в 4-ой, ни в 5-ой версии PHP, но PHP на это не ругается. Часто вследствие невнимательности, Вы можете ошибиться в написании имени свойства объекта (например, перепутать регистр букв). В случае чтения несуществующего свойства Вы получите “Notice: Undefined property: A::$MyVar in C:\1\test3.php on line 10″. А в случае присвоения значения — никаких сообщений. Просто вместо изменения значения свойства вы создадите новое свойство, которое при всем при этом будет иметь область видимости public. Отловить такую ошибку обычно довольно трудно, поэтому я предлагаю решение, которое позволяет отлавливать попытку установки значения для несуществующего свойства объекта в PHP5.
Мое решение основано на создании базового класса для всех классов, который использует перегрузку свойств посредством методов __get() и __set(). Этот базовый класс выглядит следующим образом:
<?php
class ClassBase {
protected function __get($key) {
throw new Exception('Attempt to read undefined property $'.$key.' of '.get_class($this).' class');
}
protected function __set($key, $value) {
throw new Exception('Attempt to set value to undefined property $'.$key.' of '.get_class($this).' class');
}
}
?>
И объявляем все наши классы потомками от ClassBase:
<?php
class A extends ClassBase {
}
$a = new A();
$a->MyVar = 'test';
?>
При выполнении данного примера сработает Exception, который если не отловить через try .. catch, приведет к аварийному завершению скрипта с ошибкой “Fatal error: Uncaught exception ‘Exception’ with message ‘Attempt to set value to undefined property $MyVar of A class’ in C:\work\test.php:10″.
Просто и элегантно. Строго говоря, мое решение есть ни что иное как синтаксическая соль для языка PHP5 в части работы с ООП.
