Доступ к закрытым свойствам класса в PHP
Иногда встречаются ситуации, когда нужно расширить функциональность класса сторонней библиотеки; при этом нужный класс реализован так, что вместо наследования проще переписать, ибо функциональность завязана на закрытых (private) свойствах класса, для которых он не предоставляет акцессоров.
Чтобы далеко не ходить за примером, можно посмотреть на реализацию работы с базой данных в Yii — если требуется что-то нестандартное и не предусмотренное разработчиками — придётся извращаться. Например, если нужно добавить поддержку SELECT … FOR UPDATE/SELECT … LOCK IN SHARE MODE (кстати, весьма нужный довесок для высоконагруженных сайтов с активной работой с базой данных), кажется вполне логичным унаследоваться от класса CDbCommand и добавить свои методы для организации блокировки и переопределить метод buildQuery. В теории это выглядит хорошо, но на практике имеем, что вся функциональность завязана на закрытое свойство CDbCommand::_q, в котором хранятся все параметры запроса. Кроме того, для поддержки этого хозяйства в Active Record придётся унаследоваться от CActiveRecord, а там такая же петрушка.
На правах лирического отступления: при всей моей любви к Yii, некоторые архитектурные решения выглядят весьма непродуманными и вызывают во мне любимый жест капитана Пикара: множественные косяки с закрытыми свойствами, проверки method_exists() идут вразрез с идеологией CComponent (например, использование mixin (behavior) как метода форматирования в класс, порождённый от CFormatter, закончится исключением), неудачное разбиение на методы, из-за которого наследование временами превращается в копипаст и т.д.
PHP — это не C++, поэтому антипаттерн Паблик Морозов (#define private public) здесь не пройдёт. К счастью, костылестроение в PHP поставлено на поток, поэтому решение всё же есть… Далее »
Май
2012
SQLMon для Yii
Одной из вещей, которых мне очень не хватало при разработке сайтов на Yii — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа.
Ситуацию частично исправило расширение под названием Yii DB profiler. Но остались некоторые неудобства:
- Отображение запросов в порядке убывания времени выполнения — в принципе, это дело вкуса: при таком порядке сразу видны проблемные запросы. С другой стороны, лично мне более привычен хронологический порядок — так чётче прослеживается логика работы;
- Prepared statements. Это просто здорово, но если повторять запрос в phpMyAdmin (например, если интересует план выполнения запроса), бывает очень муторно заменять все связанные значения. Например, для запросов вида
[-]View Code MySQLзаменять всеSELECT 't'."object_id" AS "t0_c0", 't'."ymd" AS "t0_c1", 't'."black" AS "t0_c2", 't'."brown" AS "t0_c3", 't'."yellow" AS "t0_c4",
't'."neutral" AS "t0_c5", 't'."white" AS "t0_c6", 't'."unknown" AS "t0_c7", 't'."error" AS "t0_c8", 'object'."object" AS "t1_c2",
'object'."id" AS "t1_c0"
FROM 'dnsbl_summary' 't'
LEFT OUTER JOIN 'objects' 'object' ON ('t'."object_id"='object'."id")
WHERE (((black > 0) OR (brown > 0)) AND
(((((((((ymd=:ycp0) AND (black>:ycp1)) AND (brown=:ycp2)) AND (yellow=:ycp3)) AND
(neutral>:ycp4)) AND (white>:ycp5)) AND (unknown=:ycp6)) AND (black>:ycp7)) AND
(error=:ycp8))) AND (object.enabled = 1)
LIMIT 50:ycpXXXна их значения немного муторно. В общем случае здесь вряд ли можно что-то сделать — заполнители параметров могут быть любыми (и даже позиционными), поэтому тупое использованиеstr_replaceможет наделать делов.
Лично мне список запросов нужен обычно только для двух вещей:
- Оценка работы механизмов кэширования;
- Оценка плана выполнения запроса, составленная оптимизатором.
Первое обычно не критично (зачастую достаточно посмотреть на количество запросов), а вот второе позволяет выявить многие будущие проблемы с производительностью заранее.
В результате, взяв за основу плагин Александра, я портировал SQLMon на Yii.
Далее »
Ноя
2011
Преобразование ошибок в PHP в исключения
Навеяно этим сообщением на форуме.
Дано:
- фреймворк перехватывает все возникающие ошибки (которые разрешены текущим значением
error_reporting()) и аварийно завершает работу скрипта (в целях отладки/безопасности/нужное подчеркнуть); - имеется код, вызывающий PHP-функцию, которая может сгенерировать предупреждение (в оригинальном сообщении это
mkdir()— кидаетE_WARNING, если не удаётся создать каталог) - местные стандарты кодирования запрещают использование оператора
@(довольно распространённая практика).
Требуется обработать возникшую ошибку без авоста скрипта. Далее »
Автор: Vladimir, опубликовано в: PHP, комментариев: 8Авг
2011
Перехват фатальных ошибок в Yii
Как и Kohana, Yii помогает разработчику, отлавливая неперехваченные исключения и ошибки в коде. Как и в Kohana, реализуется это одинаково — через функции PHP set_exception_handler() и set_error_handler(). Но, в отличие от Kohana, Yii не умеет перехватывать фатальные ошибки (E_ERROR в терминах PHP).
Как следствие, если приложение сгенерирует фатальную ошибку (например, вызов несуществующей функции), у разработчика все шансы об этом не узнать (например, на production-сервере с display_errors установленным Off). Конечно, если приложение хорошо протестировано шансы возникновения такой ситуации близки к нулю, но если приложение позволяет пользователю устанавливать какие-либо свои дополнения, то лучше узнавать о проблемах прежде, чем начальник получит кучу гневных писем
Далее »
Авг
2011
Вложенные транзакции в PDO
В PDO есть такая особенность: отсутствие поддержки вложенных транзакций.
Вложенные транзакции бывают весьма полезны: например, у нас есть два сервиса, которые могут взаимодействовать между собой. Сервис А начинает транзакцию, что-то делает, затем вызывает сервис Б, затем подтверждает транзакцию.
Может так случиться, что сервисы А и Б разрабатываются разными людьми и разработчик сервиса Б может не знать, что сервис А уже начал выполнение транзакции. Как следствие, при использовании PDO как только сервис Б попытается начать транзакцию, PDO выбросит исключение, предупреждающее о наличии активной транзакции.
Тем не менее, такие СУБД как MySQL, PostgreSQL и SQLite поддерживают вложенные транзакции (о чём PDO не знает). Поэтому было бы неплохо добавить поддержку вложенных транзакций для данных СУБД в PDO. Далее »
Автор: Vladimir, опубликовано в: PHP, комментариев: 4Авг
2011
Автоматическая проверка репутации IP-адреса
Репутация IP-адреса — одна из очень важных составляющих, используемых для борьбы с почтовым спамом.
Письма приходят с IP-адресов, а репутация этих адресов может сказать, является ли данный адрес ответственным за рассылку спама или нет. По некоторым данным проверка репутации IP-адресов позволяет остановить порядка 80% спама.
Как следствие, компании, занимающиеся массовой рассылкой электронных писем, должны заботиться о поддержании хорошей репутации адресов своих почтовых серверов. Далее »
Автор: Vladimir, опубликовано в: PHP, комментариев: 6Фев
2011
Особенности работы функции checkdnsrr()
Функция checkdnsrr() используется для проверки существования записей DNS. Например, фреймворк Kohana использует эту функцию для проверки наличия MX-записи домена, указанного в адресе электронной почты.
Тем не менее, существуют некоторые подводные камни, связанные с использованием данной функции, о которых разработчикам нужно знать. Далее »
Автор: Wandering Soul, опубликовано в: PHP, комментариев: нетСен
2010
DoS для PHP через imap_fetchbody
Как оказалось, если передать функции imap_fetchbody() параметр $secton, длина которого больше 1004 байт, PHP падает по segmentation fault. На некоторых конфигурациях с применением некоторых усилий (подробности, понятное дело, разглашаться не будут) получалось вместе с PHP положить и Apache. Далее »
Авг
2010
Исправление ошибки в INSERT INTO … SELECT в Kohana 3 при использовании конфигурации базы данных, отличной от default
Ситуация: нужно выполнить запрос вида
Если использовать конфигурацию default, то всё отлично работает. Если же использовать другую конфигурацию, то можем получить ошибку соединения с базой данных и исключение. Далее »
Авг
2010
Поддержка JOIN в запросах DELETE для Kohana 3
Иногда бывает полезно выполнить удаление записей в нескольких связанных таблицах, благо синтаксис позволяет. Разумеется, есть такая вещь как каскадное удаление записей, но в случае с MySQL (а именно — таблицами MyISAM) на неё надеяться не приходится.
Модуль Database из Kohana 3 не умеет использовать JOIN с операцией DELETE. Нужно ему помочь. Далее »
Автор: Wandering Soul, опубликовано в: Kohana, комментариев: нетАвг
2010

Меня зовут Владимир, я программист-фрилансер, специализирующийся на Web-программировании и програмировании под Linux.
По совместительству занимаюсь администрированием LAMP/LNMP-серверов и техническим переводом.

