Сравнение различных методов вызова функций в PHP
Вызов статических методов классов — прекрасная альтернатива обычным функциям - и класс создавать не нужно и принципы объектно-ориентированного программирования не нарушаются. Однако, в реализации статических методов в PHP есть несколько проблем - статические методы не всегда корректно наследуются, поэтому, чтобы нивелировать неудобства статических методов в PHP часто используют синглетоны - обертывают денимические методы статическими обертками.
Однако, создание синглетона операция довольно ресурсоёмкая — проверить создан ли экземпляр класса, создать экземпляр класса если он не создан, вызвать на нём нужный метод. Насколько это сказывается на бытродействии я и решил сегодня проверить.
Для оценки скорости доступа к методам синглетона я сделал небольшой скрипт. Скрипт генерирует тестовые последовательности вызовов функций в различных вариантах - и сравнивает время вызовов этих последовательностей.
Вот исходный код скрипта.
Результат работы скрипта представлен в таблице ниже:
generation_time | 11.7576429844 |
php_version | 5.3.2-1ubuntu4.9 |
Case | try 1 | try 2 | try 3 | try 4 | middle |
---|---|---|---|---|---|
Same plain function called 10000 times | 0.0166 | 0.0187 | 0.0183 | 0.0135 | 0.0168 |
Different plain functions called 10000 times | 0.0163 | 0.0221 | 0.018 | 0.0163 | 0.0182 |
Same static method 10000 times | 0.0193 | 0.0265 | 0.0206 | 0.0194 | 0.0214 |
Different static methods called 10000 times | 0.0221 | 0.0283 | 0.0229 | 0.0229 | 0.024 |
Static methods of different classes called 10000 times | 0.0236 | 0.0279 | 0.0251 | 0.0242 | 0.0252 |
Same dynamic method called 10000 times | 0.0166 | 0.0193 | 0.0169 | 0.0169 | 0.0174 |
Different class methods called 10000 times | 0.02 | 0.02 | 0.0202 | 0.02 | 0.02 |
Singleton method called 10000 times | 0.0403 | 0.0446 | 0.0409 | 0.041 | 0.0417 |
Different singletons called 10000 times | 0.0562 | 0.0631 | 0.0548 | 0.0572 | 0.0578 |
В тестовом скрипте, я сравнил обычные PHP функции, статические методы класса, обычные методы и методы синглетона.
Результаты тестирования показали, что вызов методов синглетона, примерно в два - четыре раза медленнее, чем вызов обычных методов, что, в принципе, меня порадовало — я ожидал, что будет хуже.
При этом выяснилось несколько дополнительных вещей: cтатические вызовы функций объявленных без модификатора "static" примерно в два раза медленнее, чем с ним, cтатические методы немного медленнее, чем динамические.
Так что, в принципе, синглетоны вполне можно использовать, особенно в случаях, когда быстродействие не сильно критично.
Странный глюк в PHP
Не знаю, сталкивался ли кто или это мне повезло, но вчера поймал загадочный баг, похоже, что в движке PHP, хотя, пока до конца не уверен.
Предыстория такая - работаю над проектом, над которым потрудились индийские программисты. Сам проект сделан на движке Symphony - добротный такой движок, вполне приятный. В качестве библиотеки работы с базой данных используется Creole - тоже довольно приятная штука. В качестве ORM используется Propel — штука громоздкая, но тем не менее тоже весьма мощная и простая. Вообще Symphony показался мне весьма неплохим движком, весьма простым и удобным. Наверно, потому, что он почти один в один копирует Ruby on Rails - те же хелперы, тот же yml в конфигах, такой же подход к MVC - в общем очень похоже.
Так вот, доблестные индийские программисты, вместо того, чтобы использовать оснастку из Symphony навставляли везде mysql_connect и mysql_query. И все бы ничего, но mysql_connect у них вставляется ВЕЗДЕ перед mysql_query — в одном скрипте может быть создано несколько десятков соединений, а каждый mysql_query дополняется проверкой "or die(mysql_error())", поэтому любая ошибка в sql ведет к скоропостижной кончине всего скрипта.
Чтобы хоть как то исправить это безобразие я сначала удалил все mysql_connect. Затем, все mysql_query поиском и заменой заменил на собственную функцию, использующую оснастку creole, поместил её в глобально видимый класс myTools::query():
static function query($sql){ $connection = Propel::getConnection(); $r = $connection->executeQuery($sql); return $r->getResource(); }
Странное дело код ведь тривиальный, но ресурс возвращаемый этой функцией оказался невалидным! Причем внутри функции ресурс еще остаётся рабочим а возвращённый во вне оказывается сломанным. Тот же код ВНЕ функции идеально работает, но как только выношу его в функцию — перестаёт работать.
Что это — глюк самого PHP или глюк Simphony я так и не понял, пришлось немного модифицировать класс MySQLConnection и добавить туда метод возвращающий MySQL ресурс непосредственно, минуя всякие PHP обёртки, но осадочек все же остался...
Какая гадость этот ваш WordPress!
Не спорю, штука прикольная, но уж больно архитектура у него специфическая:
- нет OOP: несмотря на то, что в системе вроде бы присутствуют классы - основная функциональнасть реализована на функциях;
- плохие привычки программирования: широко используются глобальные переменные;
- JavaScript ад: бардак со скриптами - доходит до того что каждый плагин тянет за собой собственный jquery или prototype;
- тем полно, но все кривые: темы сделаны по-идиотски - нет единого соглашения для создания тем, нет четкого разделения навигации и шаблонов - по сути вся навигация и функционал заложены в теме - а это половина движка;
- нет MVC: собственно нет шаблонов вообще - логика перемешана с HTML так не кодируют уже давно;
- SQL: движёк для работы с базой данных неплох - но он негибкий, заточен только под WP и только под MySQL;
- CMS: виджеты можно настраивать для всех страниц сразу, выборочно никак нельзя;
- низкое быстродействие: из-за навороченной системы фильтров и хуков в финале система получается тормозная и прожорливая;
- разработчики не подозревали о существовании других временных зонах кроме UTC: в коде жёстко прописано date_default_timezone_set('UTC');
Ruby on Rails с точки зрения PHP программиста
Изучаю RoR, в принципе нравится. Многие вещи сделаны классно но некоторые вещи вызвали у меня недоуменье:
- обязательный REST: контроллеры генерят код для HTML и для XML хотя их никто об этом не просит. Возможно это круто и обосновано, однако это приводит к избыточности в коде, и созданию функциональности, которая никогда не будет востреботвана.
- обязятельный JavaScript:удаление элементов происходим методом DELETE, хотя браузеры обычно этот метод не используют, поэтому, для вызова DELETE методов используется объект HttpRequest. Как следствие, в браузере обязательно должен быть включен JavaScript. Если JavaScript выключить стандарные методы удаления объектов перестают работать. Это - не гуд.
- избыточность в структуре проекта: методы генерации объектов создают сразу код на все случаи жизни... И что мне после этого удалять вновь созданные файлы если что то не нужно?