Персональный сайт
Романа Парпалака
  Заметки Блог Движок сайтов Игра «Жизнь»  
Главная → Блог → Ключевые слова → PHP

PHP

Статьи по этой теме:
Миниатюры на PHP
Офлайн-версия сайта, или PDF и PHP
PHP и UTF-8
If-Modified-Since и кеширование


Оптимизация памяти в PHP и функция serialize

23 декабря 2011 года, 01:43

Хорошая статья на Хабре про особенности выделения памяти в PHP. Обычно на расход памяти в php-скриптах никто не обращает внимания. Но иногда бывают ситуации, когда стандартных 16 мегабайт оказывается недостаточно. Тогда приходится изобретать различные трюки.

Не так давно я писал требовательный к памяти скрипт. Это скрипт поиска, ранняя версия которого используется на сайте правил русского языка, а адаптированная версия перекочевала в мой движок сайтов.

Я немного поколдовал с кодом и в итоге сократил потребление памяти более чем в два раза. Раньше для индексации этого сайта нужно было 32 мегабайта памяти, а теперь достаточно и 16. Кроме методов из статьи, я применил запись чисел в системе счисления по основанию 36 (перевод осуществляется функцией base_convert()) и оптимизировал функцию serialize(). Опишу последний метод подробнее.

Дело в том, что функция serialize() расходует много памяти, и об этом написано в документации. Если ей передать большой массив, доступная скрипту память может закончиться. Относительно простой выход из положения существует, когда массив нужно сохранить в файл. Функцию serialize() можно применять к отдельным элементам массива, как в следующем фрагменте кода:

file_put_contents($filename, 'a:'.count($array).':{');
$buffer = '';
$length = 0;
foreach ($array as $word => $data)
{
    $chunk = serialize($word).serialize($data);
    $length += strlen($chunk);
    $buffer .= $chunk;
    if ($length > 100000)
    {
        file_put_contents($filename, $buffer, FILE_APPEND);
        $buffer = '';
        $length = 0;
    }
}
file_put_contents($filename, $buffer.'}', FILE_APPEND);

Запись происходит порциями размером около 100 килобайт. Этот код подходит для сохранения в файл массива с большим количеством элементов среднего размера и решает проблему перерасхода памяти функцией serialize().

Ключевые слова: PHP | Оставить комментарий

Загадка специалистам по PHP

16 января 2011 года, 12:53

Как вы думаете, что выведут следующие операторы?

<?php

echo preg_match('#тес#iu', 'Такой Вот Тест');
echo preg_match('#Тес#Siu', 'Такой Вот Тест');
echo preg_match('#тес#Siu', 'Такой Вот Тест');
echo preg_match('#во#Siu', 'Такой Вот Тест');

Логика подсказывает, что 1111, а на опыте оказалось 1101. Причем и в Windows, и в Linux (Debian, PHP 5.2.6). Я подумал, что комбинация модификаторов Siu несовместима (и даже убрал в отлаживаемом коде модификатор S). Но почему тогда последнее регулярное выражение срабатывает правильно?

Кто подскажет, в чем тут дело?

Ключевые слова: PHP | Комментарии (3)

UTF-8 bad chars

10 апреля 2010 года, 01:36

Вопрос о «плохих» данных в UTF-8. Иногда такое знание оказывается полезным. Например, в корректной UTF-8 строке не могут встретиться байты 0xC0, 0xC1. Это может пригодиться при обработке строк для экранировки неизменяемых последовательностей символов (таких, как html-теги). Экранируемые подстроки вырезаются из строки, на их место ставятся символы с кодом 0xC0, строка обрабатывается, после чего подстроки возвращаются назад, вместо 0xC0.

Ключевые слова: PHP | Оставить комментарий

#.*#/u

27 января 2010 года, 19:27

У регулярных выражений PHP есть специальный модификатор u для работы со строками в кодировке UTF-8. Оказывается, вставлять этот модификатор во все подряд регулярные выражения не только бессмысленно, но и вредно. Если шаблон может работать после удаления модификатора u, то он будет работать без него быстрее, зачастую существенно быстрее.

Вообще-то, знакомства с устройством кодировки UTF-8 достаточно, чтобы понять, почему строки в этой кодировке обрабатываются медленнее. Однако я не сопоставил этот факт с тем, что неоправданное употребление модификатора u может сильно замедлить регулярное выражение, и обнаружил такое замедление случайно.

Когда же модификатор u необходим? Только тогда, когда в регулярном выражении указывается количество символов или в квадратных скобках присутствуют символы, не входящие в нижнюю половину таблицы ASCII.

В процессе оптимизации можно попытаться изменить регулярное выражение и убрать из него модификатор u.

Как всегда, лучше проверять на практике необходимость модификатора u в каждом конкретном регулярном выражении и его влияние на время выполнения скрипта.

Ключевые слова: PHP | Оставить комментарий

PHP: навигация

4 августа 2008 года, 23:57

Некоторое время назад Илья Бирман написал про подсветку ключевых слов. В комментариях после моего замечания о возможности использовать функцию preg_replace развязалась небольшая дискуссия о том, как правильно нужно генерировать подобные вещи. Вот что писал Илья:

*_replace — это вообще не наш метод, надо сразу всё правильно генерировать, а не резать по живому потом.

А генерировать неправильный контент, чтобы потом его героически исправить — это левак, нужно сразу генерировать правильный.

Рассмотрим достоинства и недостатки различных подходов к генерации контента на простом примере навигационных ссылок.

Использование preg_replace позволяет сделать код коротким и понятным.

$cur_url = 'item2.htm';

$menu = '<a href="item1.htm">item1</a><br />
<a href="item2.htm">item2</a><br />
<a href="item3.htm">item3</a><br />
<a href="item4.htm">item4</a><br />
<a href="item5.htm">item5</a>';

$menu = preg_replace(
	'#<a href="'.$cur_url.'">([^<]*)</a>#',
	'<span>\\1</span>',
	$menu);

Однако на мой взгляд этот код может быть расценен в соответствии с цитатой как «левак». Я не знаю, какой способ является правильным в этой ситуации с точки зрения Ильи, но могу предположить, что он должен быть примерно таким:

$cur_url = 'item2.htm';

$menu_array = array(
	'item1.htm' => 'item1',
	'item2.htm' => 'item2',
	'item3.htm' => 'item3',
	'item4.htm' => 'item4',
	'item5.htm' => 'item5'
);

$menu = '';
foreach ($menu_array as $url => $link) {
	if ($url != $cur_url)
		$menu .= '<a href="'.$url.'">'.$link.'</a><br />';
	else
		$menu .= '<span>'.$link.'</span><br />';
}

Этот код является чуть более громоздким. К тому же, у метода не всё в порядке с производительностью. Проведенные тесты показали, что он примерно в три раза медленнее, чем предыдущий.

Можно применить и третий способ:

$cur_url = 'item2.htm';

if ($url != 'item1.htm')
	$menu = '<a href="item1.htm">item1</a><br />';
else
	$menu = '<span>item1</span><br />';

if ($url != 'item2.htm')
	$menu .= '<a href="item2.htm">item2</a><br />';
else
	$menu .= '<span>item2</span><br />';

if ($url != 'item3.htm')
	$menu .= '<a href="item3.htm">item3</a><br />';
else
	$menu .= '<span>item3</span><br />';

if ($url != 'item4.htm')
	$menu .= '<a href="item4.htm">item4</a><br />';
else
	$menu .= '<span>item4</span><br />';

if ($url != 'item5.htm')
	$menu .= '<a href="item5.htm">item5</a>';
else
	$menu .= '<span>item5</span>';

Он еще более громоздкий, да еще и избыточный. Хотя данный способ в полтора раза быстрее первого, в подобной ситуации я отдаю предпочтение использованию preg_replace.

Ключевые слова: PHP | Комментарии (6)

PHP и timestamp

24 июля 2008 года, 18:18

На мой взгляд, функции time(), mktime(), date(), gmmktime(), gmdate() недостаточно хорошо описаны в документации. Легко запутаться при попытках понять, что же происходит в разных часовых поясах. Вот доходчивое объяснение (правда, на английском). Вкратце его суть в следующем. Метка времени (timestamp) фиксированного момента одна и та же для всех часовых поясов. Функции date() и mktime() преобразуют timestamp ко времени в часовом поясе, установленном на сервере, и обратно. Функции gmdate() и gmmktime() делают то же самое, но только для гринвичского времени.

Ключевые слова: PHP | Оставить комментарий

PHP: mkdir

3 июля 2008 года, 18:09

Сегодня потратил немало времени в попытках понять, почему права у директории dir после выполнения функции mkdir('dir', 0777); не выставляются в 777. А ведь в документации написано:

На аргумент mode также влияет текущее значение umask, которое можно изменить при помощи umask().

Тема umask осталась нераскрытой. В общем, про второй параметр у функции mkdir() можно забыть, а правильный код выглядит так:

mkdir('dir');
chmod('dir', 0777);
Ключевые слова: PHP | Комментарии (5)
ПнВтСрЧтПтСбВс
12345
6789101112
13141516171819
20212223242526
272829
Записи
Посетителям
наверх