Задача: Проверить насколько перегруженные методы и свойства медленнее явных.
Публичные методы
Набросаем небольшой класс:
class Classic {
public $fooProp;
public $barProp;
public function getFooProp() {
return $this->fooProp;
}
public function setFooProp($foo) {
$this->fooProp = $foo;
}
public function getBarProp() {
return $this->barProp;
}
public function setBarProp($bar) {
$this->barProp = $bar;
}
}
Проведем тест на скорость выполнения публичных методов. Исходя из
$iterations = 10000;
echo '
Доступ через прописанные сеттеры/геттеры - ';
$time_start = microtime(1);
for ($i=0; $i < $iterations; $i++) {
$obj = new Classic();
$obj->setFooProp($i);
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
}
$times = round($iterations / (microtime(1) - $time_start));
echo $times . ' в секунду
';
Результаты тестов на 10000 итераций:
Доступ через прописанные сеттеры/геттеры - 136552 в секунду
Перегрузка обращений к свойствам объекта (__set, __get)
Класс Overloaded реализует функционал класса Classic, с помощью перегрузки методов(__call) и доступа к свойствам(__set, __get):
Overloaded {
protected $fields = array(
'fooProp' => false,
'barProp' => false
);
protected function _generateNoPropertyException($prop) {
throw new Exception('Undefined property ' . $prop);
}
public function __get($name) {
if(isset($this->fields[$name])) {
return $this->fields[$name];
} else {
$this->_generateNoPropertyException($name);
}
}
public function __set($name,$value) {
if (isset($this->fields[$name])) {
$this->fields[$name] = $value;
} else {
$this->_generateNoPropertyException($name);
}
}
public function getBarProp() {
return $this->fields['barProp'];
}
protected function __call($mthd, $args = array()) {
$type = substr($mthd, 0, 3);
if('get' == $type) {
return $this->__set(strtolower(substr($mthd, 3, 1)).substr($mthd, 4),$args);
} elseif('set' == $type) {
return $this->__get(strtolower(substr($mthd, 3, 1)).substr($mthd, 4));
}
throw new Exception("No such method '$mthd' in " . get_class($this));
}
}
Протестируем:
echo '
Доступ через перегруженные сеттеры/геттеры - ';
$time_start = microtime(1);
for ($i=0; $i < $iterations; $i++) {
$obj = new Overloaded();
$obj->fooProp = $i;
$tmp = $obj->barProp;
$tmp = $obj->fooProp;
$tmp = $obj->barProp;
$tmp = $obj->fooProp;
$tmp = $obj->barProp;
$tmp = $obj->fooProp;
$tmp = $obj->barProp;
$tmp = $obj->fooProp;
$tmp = $obj->barProp;
}
$times = round($iterations / (microtime(1) - $time_start));
echo $times . ' в секунду
';
Получаем результат:
Доступ через перегруженные сеттеры/геттеры - 56004 в секунду
Перегрузка методов (__call)
Тестировать будем на нашем классе Overloaded:
echo ‘
Доступ через эмулированные сеттеры/геттеры – ‘
;
$time_start = microtime(1);
for ($i=0; $i < $iterations; $i++) {
$obj = new Overloaded();
$obj->setFooProp($i);
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
$tmp = $obj->getFooProp();
$tmp = $obj->getBarProp();
}
$times = round($iterations / (microtime(1) – $time_start));
echo $times . ‘ в секунду’;
highlight_file(__FILE__);
Результат:
Доступ через эмулированные сеттеры/геттеры - 27468 в секунду
Выводы
Вот результаты всех трех тестов:
Доступ через прописанные сеттеры/геттеры - 136552 в секунду
Доступ через перегруженные сеттеры/геттеры - 56004 в секунду
Доступ через эмулированные сеттеры/геттеры - 27468 в секунду
На диаграмме это выглядит следующим образом:

Сравнительно большая разница. Но если учесть, что сервер на котором проводилось тестирование достаточно сильно загружен, и тем не менее способен ежесекундно обрабатывать примерно 27,5 тысяч объектов, то отказ от использования overload это экономия на спичках в чистом виде.
Исходники полного теста: setget.php (3,2 Кб)