Заметки, Проекты → Сравниваем классы в php
Давно хотел сравнить между собой обычные методы классов и статичные, но все руки не доходили. Сегодня вот столкнулся с приватным фреймворком, в котором ВСЕ методы и параметры статичные. Вообще все, т.е. нет ни одного обычного объекта! Откладывать сравнение было уже нельзя, чем я и занялся утром. Результаты неоднозначные, даже странные для меня, местами. В общем, «непоняно» что и как… На Ваш суд выношу результаты тестов, а Вы попробуйте мне объяснить почему результаты именно такие. Кстати, я не буду сравнивать размер используемой памяти, т.к. тут как-раз все понятно — статичные методы и свойства явно будут меньше кушать памяти. Это понятно.
Итак, начнем. Для начала, попробуем сравнить между собой «сферических конец в вакууме», т.е. классы-пустышки. Код у нас получится примерно такой:
<?php
class ClassStatic {
public static function test() {
;
}
}
class ClassDinamic {
public function test() {
;
}
}
$static = array();
$dinamic = array();
for ($count = 0; $count < 100; $count++) {
$start = microtime(TRUE);
for ($i = 0; $i <= 1000; $i++)
ClassStatic::test();
$static[$count] = microtime(TRUE) - $start;
$start = microtime(TRUE);
$obj = new ClassDinamic();
for ($i = 0; $i <= 1000; $i++)
$obj -> test();
$dinamic[$count] = microtime(TRUE) - $start;
}
echo 'Static: min - ' . min($static) . '; max - ' . max($static) . '; avg - ' . array_sum($static) / 100 . "<br />\n";
echo 'Dinamic: min - ' . min($dinamic) . '; max - ' . max($dinamic) . '; avg - ' . array_sum($dinamic) / 100 . "<br />\n";
Результаты пустышек довольно предсказуемы (опять-таки, для меня) — статичные методы медленнее обычных, примерно на 13%:
Static:
min: 0.00373196601868; max: 0.00434994697571; avg: 0.0038482427597Dinamic:
min: 0.00326490402222; max: 0.00377583503723; avg: 0.00335712432861
Но, тестировать пустышки бесполезно, верно? Попробуем что-то делать и сравнить. Я выбрал md5 от случайных чисел:
<?php
class ClassStatic {
public static function test() {
return md5(mt_rand(1, 99999));
}
}
class ClassDinamic {
public function test() {
return md5(mt_rand(1, 99999));
}
}
$static = array();
$dinamic = array();
for ($count = 0; $count < 100; $count++) {
$start = microtime(TRUE);
for ($i = 0; $i <= 1000; $i++)
ClassStatic::test();
$static[$count] = microtime(TRUE) - $start;
$start = microtime(TRUE);
$obj = new ClassDinamic();
for ($i = 0; $i <= 1000; $i++)
$obj -> test();
$dinamic[$count] = microtime(TRUE) - $start;
}
echo 'Static: min - ' . min($static) . '; max - ' . max($static) . '; avg - ' . array_sum($static) / 100 . "<br />\n";
echo 'Dinamic: min - ' . min($dinamic) . '; max - ' . max($dinamic) . '; avg - ' . array_sum($dinamic) / 100 . "<br />\n";
Результат не сильно отличается, что довольно предсказуемо. Но средняя разница во времени выполнения сократилась до 6%:
Static:
min: 0.00973296165466; max: 0.0118901729584; avg: 0.0100108170509Dinamic:
min: 0.00917601585388; max: 0.0104711055756; avg: 0.00944202184677
Стало уже немного интереснее, т.к. я ожидал немного иного — ожидал, что разница увеличится не в пользу static. Этого не произошло. Ладно, идем дальше. До этого тестил вызов одного метода, теперь захотелось проверить, как отразится добавление параметра класса на скорость выполнения (забегая вперед, скажу, что на скорость практически не влияет видимость параметра). Убираю md5 и считаю числа — так правильнее, на мой взгляд (да и быстрее)):
<?php
class ClassStatic {
protected static $result = 0;
public static function test() {
self::$result += mt_rand(1, 99999);
}
}
class ClassDinamic {
protected $result = 0;
public function test() {
$this -> result += mt_rand(1, 99999);
}
}
$static = array();
$dinamic = array();
for ($count = 0; $count < 100; $count++) {
$start = microtime(TRUE);
for ($i = 0; $i <= 1000; $i++)
ClassStatic::test();
$static[$count] = microtime(TRUE) - $start;
$start = microtime(TRUE);
$obj = new ClassDinamic();
for ($i = 0; $i <= 1000; $i++)
$obj -> test();
$dinamic[$count] = microtime(TRUE) - $start;
}
echo 'Static: min - ' . min($static) . '; max - ' . max($static) . '; avg - ' . array_sum($static) / 100 . "<br />\n";
echo 'Dinamic: min - ' . min($dinamic) . '; max - ' . max($dinamic) . '; avg - ' . array_sum($dinamic) / 100 . "<br />\n";
Результаты следующие:
Static:
min: 0.00786805152893; max: 0.0100691318512; avg: 0.00815812349319Dinamic:
min: 0.00634098052979; max: 0.0100259780884; avg: 0.00662218570709
Средняя разница составила почти 19%. Это нормально… Идем дальше: добавляем еще по одному методу:
<?php
class ClassStaticTwo {
public static function operation() {
return mt_rand(1, 99999);
}
}
class ClassStatic {
protected static $result = 0;
protected static function operation() {
return mt_rand(1, 99999);
}
public static function test() {
self::$result += self::operation();
}
}
class ClassDinamic {
protected $result = 0;
protected function operation() {
return mt_rand(1, 99999);
}
public function test() {
$this -> result += $this -> operation();
}
}
$static = array();
$dinamic = array();
for ($count = 0; $count < 100; $count++) {
$start = microtime(TRUE);
for ($i = 0; $i <= 1000; $i++)
ClassStatic::test();
$static[$count] = microtime(TRUE) - $start;
$start = microtime(TRUE);
$obj = new ClassDinamic();
for ($i = 0; $i <= 1000; $i++)
$obj -> test();
$dinamic[$count] = microtime(TRUE) - $start;
}
echo 'Static: min - ' . min($static) . '; max - ' . max($static) . '; avg - ' . array_sum($static) / 100 . "<br />\n";
echo 'Dinamic: min - ' . min($dinamic) . '; max - ' . max($dinamic) . '; avg - ' . array_sum($dinamic) / 100 . "<br />\n";
Результаты стали значительно ровнее и ближе:
Static:
min: 0.011332988739; max: 0.0122909545898; avg: 0.0115933132172Dinamic:
min: 0.0104849338531; max: 0.0119299888611; avg: 0.0108146929741
В принципе, в этот момент я уже был уверен, что использование статичных методов замедляет приложение. Но, для очистки совести, решил запустить тест посложнее:
<?php
class ClassStaticTwo {
public static function operation() {
return mt_rand(1, 99999);
}
}
class ClassStatic {
protected static $result = 0;
public static function test($num) {
self::$result += $num;
}
}
class ClassDinamicTwo {
public function operation() {
return mt_rand(1, 99999);
}
}
class ClassDinamic {
protected $result = 0;
public function test($num) {
$this -> result += $num;
}
}
$static = array();
$dinamic = array();
for ($count = 0; $count < 100; $count++) {
$start = microtime(TRUE);
for ($i = 0; $i <= 1000; $i++)
ClassStatic::test(ClassStaticTwo::operation());
$static[$count] = microtime(TRUE) - $start;
$start = microtime(TRUE);
$obj = new ClassDinamic();
$obj2 = new ClassDinamicTwo();
for ($i = 0; $i <= 1000; $i++)
$obj -> test($obj2 -> operation());
$dinamic[$count] = microtime(TRUE) - $start;
}
echo 'Static: min - ' . min($static) . '; max - ' . max($static) . '; avg - ' . array_sum($static) / 100 . "<br />\n";
echo 'Dinamic: min - ' . min($dinamic) . '; max - ' . max($dinamic) . '; avg - ' . array_sum($dinamic) / 100 . "<br />\n";
Результаты сильно не изменились, не смотря на добавление дополнительных классов:
Static:
min: 0.0130889415741; max: 0.0148260593414; avg: 0.0134398984909Dinamic:
min: 0.0118761062622; max: 0.0135319232941; avg: 0.0122007513046
На этом я тесты закончил, т.к. подтвердил свое мнение. Если можете что-то предложить — говорите, протестим.
P.S.: часть тестов проводил днем на работе, часть сейчас дома. Уже не помню, какие именно были тесты на работе, но результаты СИЛЬНО отличались. Пару раз получилось так, что статичные методы были БЫСТРЕЕ обычных! Дома, к сожалению, мне это повторить не удалось (((
P.S.S.: тестировал на sony vaio z + win7x32 + denwer.