Перегрузка методов и свойств в PHP
Задача: Проверить насколько перегруженные методы и свойства медленнее явных.
Публичные методы
Набросаем небольшой класс: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 '<p>Доступ через прописанные сеттеры/геттеры - '; $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 . ' в секунду</p>';Результаты тестов на 10000 итераций:
Доступ через прописанные сеттеры/геттеры - 136552 в секунду
Перегрузка обращений к свойствам объекта (__set, __get)
Класс Overloaded реализует функционал класса Classic, с помощью перегрузки методов(__call) и доступа к свойствам(__set, __get):<?php class 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 '<p>Доступ через перегруженные сеттеры/геттеры - '; $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 . ' в секунду</p>';Получаем результат:
Доступ через перегруженные сеттеры/геттеры - 56004 в секунду
Перегрузка методов (__call)
Тестировать будем на нашем классе Overloaded: echo '<p>Доступ через эмулированные сеттеры/геттеры - '; $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 . ' в секунду</p>'; highlight_file(__FILE__); Результат:Доступ через эмулированные сеттеры/геттеры - 27468 в секунду
Выводы
Вот результаты всех трех тестов:Доступ через прописанные сеттеры/геттеры - 136552 в секунду Доступ через перегруженные сеттеры/геттеры - 56004 в секунду Доступ через эмулированные сеттеры/геттеры - 27468 в секундуНа диаграмме это выглядит следующим образом:
Сравнительно большая разница. Но если учесть, что сервер на котором проводилось тестирование достаточно сильно загружен, и тем не менее способен ежесекундно обрабатывать примерно 27,5 тысяч объектов, то отказ от использования overload это экономия на спичках в чистом виде.
Исходники полного теста: setget.php (3,2 Кб)

0 комментариев:
Отправить комментарий