Category Archives: php
Статический анализ PHP-кода с помощью HipHop
Нашёл на хабре статью про интересное использование HipHop, вот её текст: Неожиданно не нашёл информации на русском языке о такой замечательной возможности HipHop, как статический анализ кода для PHP, а потому встречайте обзор, на идею которого меня натолкнула презентация Расмуса на DevConf. А как это вообще? Статический анализ кода — вещь весьма полезная, ведь иначе ошибку …
Алгоритм конкатенации js-файлов для каждой страницы на лету
Хочется сделать один js-файл на страницу. Думаю над таким алгоритмом. Сразу после процедуры деплоя пользователи грузят кучу отдельных js-файлов, всё как обычно. Первый пользователь, зашедший на страницу, ставит lock в кэш (на 1 минуту), означающий, что именно ему повезло создать единый js-файл. При генерации страницы пути всех подключаемых js-файлов сохраняются в массивчик (у нас уже …
PHP coding style
Описал часть своего code style для PHP. To be updated.
PHP Fatal error: Exception thrown without a stack frame in Unknown on line 0
Отличная ошибка, на которую обычно просто «забивают», т. к. не понятно, где и что искать. А ошибка вызвана тем, что в кастомном обработчике исключений происходит исключение, после чего php прерывает процесс с таким замечательным и информативным сообщением об ошибке. В моём случае это было своё расширение для класса DateTime
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public function __construct( $Time = 'now', DateTimeZone $Timezone = null ) { // PHP 5.3.3 имеет этот баг: // @link https://bugs.php.net/bug.php?id=52063 // поэтому пишем странное: if ( ! empty( $Timezone ) ) { parent::__construct( $Time, $Timezone ); } else { parent::__construct( $Time ); } // ещё раз вызываем явно setTimezone, чтобы обойти багу с timestamp - @link http://www.php.net/manual/en/datetime.construct.php#97724 if ( empty( $Timezone ) ) { $this->setTimezone( new DateTimeZone( 'Europe/Moscow' ) ); } } |
Если не написать тот странный …
IoC в php
Читал-читал про инверсию управления (Inversion of Control), всякие Pico и Phemto.
Баги в библиотеке memcached (getMulti)
Долго боролись с багом при использовании Memcached::getMulti в php 5.3.8. Как это было: Сначала данные складываются в кэш под некоторыми ключами, потом происходит считывание
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$cached = cache->getMulti( $cacheKeys ); foreach ( $actions as &$action ) { $actionCacheKey = self::getCacheKey( $action ); if ( array_key_exists( $actionCacheKey, $cached ) ) { $action = $cached[$actionCacheKey]; } else if ( in_array( $actionCacheKey, array_keys( $cached ) ) ) { die( '!!' ); } else { $action = self::factory( $action ); } } |
Так вот, if ( array_key_exists( $actionCacheKey, $cached ) ) не отрабатывает никогда (равно как isset и ! empty). При этом условие else if ( in_array( $actionCacheKey, array_keys( $cached ) ) …
Удобная работа с датами в php
Периодически возникают задачи типа вернуть дату «первого числа прошлого месяца», или «прошлого понедельника». Это можно решить как-то так:
1 2 3 4 5 6 7 8 9 |
$dt = self::getCurrentMonthStartDt(); $dt->setTime( 0, 0, 0 ); $dt->setDate( $dt->format( 'Y' ), $dt->format( 'm' ) - 1, 1 ); return $dt; ... $dt = new DateTime(); $dt->modify( '-' . ( $dt->format( 'N' ) - 8 ) . ' days' ); $dt->setTime( 0, 0, 0 ); return $dt; |
А можно гораздо проще:
1 2 3 4 5 6 7 |
$dt = new DateTime( 'first day of last month' ); $dt->setTime( 0, 0, 0 ); return $dt; ... $dt = new DateTime( 'mon this week' ); $dt->setTime( 0, 0, 0 ); return $dt; |
It’s a kinda magic, но работает. http://www.php.net/manual/ru/datetime.formats.relative.php
Проблема при работе с расширением memcached в php
Работал раньше сайт с memcache. Решили перейти на memcached. И повалились ошибки SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY, причём сначала одна CLIENT ERROR, а уже потом куча SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY. Гугление ничего не дало, а проблема оказалась в следующем: первая ошибка возникала из-за некорректного ключа (пробел …
Борьба с утечками памяти в php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$limit = 512; $thresholdDelta = 10; ini_set('memory_limit', $limit . 'm'); ... $memoryThresholdReached = false; $memoryThreshold = ( $limit - $thresholdDelta ) * 1024 * 1024; ... while ( $user = $db->plain_fetch( $result ) ) { ... // тут работа с данными ... // проверка на превышение опасного порога использования памяти if ( ! $memoryThresholdReached && memory_get_usage( true ) > $memoryThreshold ) { $memoryThresholdReached = true; try { throw new SystemException( 'Превышен порог использования памяти...' ); } catch ( Exception $e ) {} } } |
Более серьёзные способы — просмотр стека (strace -f -p $pid) и дебаг php C-шным дебаггером DBG.
Как настроить Smarty для удобной работы (+наследование)
Smarty — странноватый и глючноватый шаблонизатор, если сравнивать с Django. Но под php ничего под руку не попалось, чтобы работало из коробки, было просто в настройке, и, к тому же, когда-то давно я его уже ковырял. В общем, нужно было срочно прикрутить шаблонизатор — сделал следующее. В классе, ответственном за вывод:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
private static function getSmarty( array $Params ) { require_once( SMARTY . 'Smarty.class.php' ); $smarty = new Smarty(); $smarty->error_reporting = E_ALL & ~E_NOTICE; $smarty->force_compile = true; $smarty->left_delimiter = '{{'; $smarty->right_delimiter = '}}'; $smarty->template_dir = TEMPLATE; foreach ( $Params as $key => $value ) { $smarty->assign( $key, $value ); } return $smarty; } public function renderToView( rController $Controller, $Debug = false ) { $contentType = $Controller->getContentType(); self::setHeaders( $contentType ); switch ( $contentType ) { case self::CONTENT_TYPE_JSON : echo json_encode( $Controller->getTemplateData() ); break; case self::CONTENT_TYPE_HTML : default : $templatePath = $Controller->getTemplatePath(); if ( ! $templatePath ) { $templatePath = $this->generateTemplatePath( $Controller ); } if ( ! file_exists( TEMPLATE . $templatePath ) ) { if ( $Debug ) { echo 'tried ' . TEMPLATE . $templatePath; } $templatePath = $this->defaultTemplatePath; } self::getSmarty( $Controller->getTemplateData() )->display( $templatePath ); } } |
Во вьюхе:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// layout.tpl <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <head> <title>{{if isset( $title )}}{{$title}}{{else}}{{$defaultTitle}}{{/if}}</title> <script type="text/javascript" src="/js/main.js"></script> {{block name="head"}}{{/block}} </head> <body> {{block name="content"}}{{/block}} </body> // index.tpl {{extends 'layout.tpl'}} {{block name="content"}} {{assign 'myparamm' 'Bob'}} myparamm {{$myparamm}} {{/block}} |
…