<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Ars Longa, Vita Brevis &#187; производительность</title>
	<atom:link href="http://blog.sjinks.pro/tag/performance/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.sjinks.pro</link>
	<description>Quod scripsi, scripsi</description>
	<lastBuildDate>Mon, 06 Feb 2012 17:56:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>SQLMon для Yii</title>
		<link>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/</link>
		<comments>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/#comments</comments>
		<pubDate>Tue, 22 Nov 2011 15:02:18 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Yii]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQLMon]]></category>
		<category><![CDATA[лог]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=947</guid>
		<description><![CDATA[Расширение для анализа производительности SQL-запросов для Yii Одной из вещей, которых мне очень не хватало при разработке сайтов на Yii — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа. Ситуацию частично исправило расширение под названием Yii DB profiler. Но остались некоторые неудобства: Отображение запросов в порядке убывания времени выполнения — в принципе, это [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Расширение для анализа производительности SQL-запросов для <a href="http://blog.sjinks.pro/tag/yii/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  Yii">Yii</a></em></h2>
<p>Одной из вещей, которых мне очень не хватало при разработке сайтов на Yii — нормального отображения всех запросов к базе данных, что дало бы возможность их последующего анализа.</p>
<p>Ситуацию частично исправило расширение под названием <a href="http://rmcreative.ru/blog/post/yii-db-profiler">Yii DB profiler</a>. Но остались некоторые неудобства:</p>
<ul>
<li>Отображение запросов в порядке убывания времени выполнения — в принципе, это дело вкуса: при таком порядке сразу видны проблемные запросы. С другой стороны, лично мне более привычен хронологический порядок — так чётче прослеживается логика работы;</li>
<li>Prepared statements. Это просто здорово, но если повторять запрос в phpMyAdmin (например, если интересует план выполнения запроса), бывает очень муторно заменять все связанные значения. Например, для запросов вида
          
<div class="codebox">
    <div class="the_code" style="" id="p9475">
        <div class="code mysql" id="p947code5">
<span class="kw1">SELECT</span> <span class="st0">'t'</span>.<span class="st0">&quot;object<span class="es1">_</span>id&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c0&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;ymd&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c1&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;black&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c2&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;brown&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c3&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;yellow&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c4&quot;</span><span class="sy2">,</span> <br />
<span class="st0">'t'</span>.<span class="st0">&quot;neutral&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c5&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;white&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c6&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;unknown&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c7&quot;</span><span class="sy2">,</span> <span class="st0">'t'</span>.<span class="st0">&quot;error&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t0<span class="es1">_</span>c8&quot;</span><span class="sy2">,</span> <span class="st0">'object'</span>.<span class="st0">&quot;object&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t1<span class="es1">_</span>c2&quot;</span><span class="sy2">,</span><br />
<span class="st0">'object'</span>.<span class="st0">&quot;id&quot;</span> <span class="kw1">AS</span> <span class="st0">&quot;t1<span class="es1">_</span>c0&quot;</span><br />
<span class="kw1">FROM</span> <span class="st0">'dnsbl<span class="es1">_</span>summary'</span> <span class="st0">'t'</span> <br />
<span class="kw13">LEFT</span> <span class="kw1">OUTER</span> <span class="kw1">JOIN</span> <span class="st0">'objects'</span> <span class="st0">'object'</span> <span class="kw1">ON</span> <span class="br0">&#40;</span><span class="st0">'t'</span>.<span class="st0">&quot;object<span class="es1">_</span>id&quot;</span><span class="sy1">=</span><span class="st0">'object'</span>.<span class="st0">&quot;id&quot;</span><span class="br0">&#41;</span> <br />
<span class="kw1">WHERE</span> <span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span>black <span class="sy1">&gt;</span> 0<span class="br0">&#41;</span> <span class="kw10">OR</span> <span class="br0">&#40;</span>brown <span class="sy1">&gt;</span> 0<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span><span class="br0">&#40;</span>ymd<span class="sy1">=</span>:ycp0<span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>black<span class="sy1">&gt;</span>:ycp1<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>brown<span class="sy1">=</span>:ycp2<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>yellow<span class="sy1">=</span>:ycp3<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span>neutral<span class="sy1">&gt;</span>:ycp4<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>white<span class="sy1">&gt;</span>:ycp5<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>unknown<span class="sy1">=</span>:ycp6<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>black<span class="sy1">&gt;</span>:ycp7<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <br />
<span class="br0">&#40;</span>error<span class="sy1">=</span>:ycp8<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="kw10">AND</span> <span class="br0">&#40;</span>object.enabled <span class="sy1">=</span> 1<span class="br0">&#41;</span><br />
<span class="kw1">LIMIT</span> <span class="nu0">50</span>
        </div>
    </div>
</div>

заменять все <code>:ycpXXX</code> на их значения немного муторно. В общем случае здесь вряд ли можно что-то сделать — заполнители параметров могут быть любыми (и даже позиционными), поэтому тупое использование <code>str_replace</code> может наделать делов.
</li>
</ul>
<p>Лично мне список запросов нужен обычно только для двух вещей:</p>
<ol>
<li>Оценка работы механизмов кэширования;</li>
<li>Оценка плана выполнения запроса, составленная оптимизатором.</li>
</ol>
<p>Первое обычно не критично (зачастую достаточно посмотреть на количество запросов), а вот второе позволяет выявить многие будущие проблемы с производительностью заранее.</p>
<p>В результате, взяв за основу <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> <a href="http://rmcreative.ru/">Александра</a>, я портировал <a href="http://blog.sjinks.pro/tag/sqlmon/">SQLMon</a> на Yii.<br />
<span id="more-947"></span></p>
<p>В результате получилось расширение, позволяющее получать планы выполнения запросов в реальном времени.</p>
<p>Поддерживаются <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a> и SQLite, в планах поддержка PgSQL (там не всё просто, ибо Postgres <em>выполняет</em> запрос, что может привести к интересным последствиям при использовании <code>INSERT</code>/<code>UPDATE</code>/<code>DELETE</code>; как следствие, придётся использовать <a href="http://blog.sjinks.pro/php/932-pdo-nested-transactions/">вложенные транзакции</a>).</p>
<p>Вывод результатов осуществляется либо при помощи виджета:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9476">
        <div class="code php" id="p947code6">
<span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">widget</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'ext.sqlmon.components.SQLMon'</span><br />
&nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'explain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения запроса</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'backtrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'dsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения (может быть полезно при использовании нескольких БД)</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'cssFile'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="co1">// Эстеты могут задать свой файл стилей </span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Либо при помощи Log Route:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9477">
        <div class="code php" id="p947code7">
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'components'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'log'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'routes'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'class'</span> <span class="sy0">=&gt;</span> <span class="st_h">'ext.sqlmon.components.SQLMonLogRoute'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showExplain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showDsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showBacktrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'class'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="st_h">'ext.sqlmon.components.SQLMonFileLogRoute'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'logFile'</span> <span class="sy0">=&gt;</span> <span class="st_h">'sqlmon.log'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showExplain'</span> &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать план выполнения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showDsn'</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать DSN соединения</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'showBacktrace'</span> <span class="sy0">=&gt;</span> <span class="kw4">true</span><span class="sy0">,</span> <span class="co1">// Показывать трассу вызовов</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p><code>SQLMonLogRoute</code> наследуется от <code>CWebLogRoute</code>, но, как и <code>CProfileLogRoute</code>, отказывается выдавать данные для AJAX-запросов.</p>
<p><code>SQLMonFileLogRoute</code> наследуется от <code>CFileLogRoute</code> и, как следствие, воспринимает все параметры конфигурации последнего.</p>
<p>Для того, чтобы протоколирование нормально работало, сообщения от <a href="http://blog.sjinks.pro/tag/sqlmon/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  SQLMon">SQLMon</a> попадают в общий протокол и, как следствие, видны при использовании <code>CWebLogRoute</code> (в этом случае выдаётся минимум информации).</p>
<p>Результаты работы выглядят примерно так (пример приведён для SQLite):</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-yii.png"><img src="http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-yii-300x283.png" alt="Пример выдачи SQLMon" title="SQLMon в Yii" width="300" height="283" class="alignnone size-medium wp-image-948" /></a></p>
<p>Реализовано всё через собственный класс PDO, поэтому для использования SQLMon нужно в файл конфигурации добавить такие строки:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p9478">
        <div class="code php" id="p947code8">
<br />
<span class="kw1">return</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; <span class="st_h">'import'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'ext.sqlmon.components.*'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<br />
&nbsp; &nbsp; <span class="st_h">'components'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'db'</span> <span class="sy0">=&gt;</span> <span class="kw1">array</span><span class="br0">&#40;</span><br />
<span class="co1">// ...</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="st_h">'pdoClass'</span> <span class="sy0">=&gt;</span> <span class="st_h">'SQLMonPDO'</span><span class="sy0">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
&nbsp; &nbsp; <span class="br0">&#41;</span><span class="sy0">,</span><br />
<span class="br0">&#41;</span><span class="sy0">;</span>
        </div>
    </div>
</div>

<p>Реализация просмотра выполнения плана выполнения запроса осуществляется при помощи класса-наследника от <code>PDOStatement</code> и переопределения метода <code>PDO::prepare()</code>.</p>
<p>Планы на будущее:</p>
<ul>
<li>поддержка PostgreSQL;</li>
<li>возможность расширения классов <code>SQLMonPDO</code> и <code>SQLMonPDOStatement</code> (возможно, придётся позаимствовать некоторые идеи из Kohana);</li>
<li>наследование <code>SQLMon_Explainer_Base</code> от <code>CComponent</code>, что даст дополнительные плюшки для расширяемости;</li>
<li>более красивая реализация функции SQLMon::arr2pre(), что позволит рисовать красивые ASCII-таблички;</li>
<li>возможная поддержка FireBug;</li>
<li>протоколирование в <a href="http://blog.sjinks.pro/tag/html/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  HTML">HTML</a>-файл;</li>
<li>информация профайлера MySQL (нужность пока под большим вопросом);</li>
<li>рефакторинг, написание документации</li>
</ul>
<p><strong><a href='http://static.sjinks.info/wp-content/uploads/2011/11/sqlmon-0.1.zip'>SQLMon 0.1 for Yii</a></strong> — скачать бесплатно без регистрации без смс <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/yii/947-sqlmon-for-yii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>KSES в WordPress: можно ли проще?</title>
		<link>http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/</link>
		<comments>http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/#comments</comments>
		<pubDate>Thu, 10 Feb 2011 06:07:09 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[KSES]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=894</guid>
		<description><![CDATA[Регулярные выражения против DOM XML Вчера мне довелось разбираться с тем, как работает KSES в WordPress. KSES (рекурсивный акроним от KSES Strips Evil Scripts) — подсистема в WordPress (изначально написанная Ulf Harnhammar), предназначенная для проверки и очистки текста, введённого пользователем: она позволяет задать список допустимых тэгов, стилей и протоколов и на основе этих параметров убрать из текста [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Регулярные выражения против DOM XML</em></h2>
<p>Вчера мне довелось разбираться с тем, как работает <a href="http://blog.sjinks.pro/tag/kses/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  KSES">KSES</a> в <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a>.</p>
<p>KSES (рекурсивный акроним от KSES Strips Evil Scripts) — подсистема в WordPress (изначально написанная Ulf Harnhammar), предназначенная для проверки и очистки текста, введённого пользователем: она позволяет задать список допустимых тэгов, стилей и протоколов и на основе этих параметров убрать из текста пользователя всё, что им не соответствует.</p>
<p>KSES является довольно стабильной подсистемой; что немаловажно, KSES <em>работает</em>. Работает —  не трогай, а то сломаешь…<span id="more-894"></span></p>
<p>Лично мне в KSES не нравится использование регулярных выражений. Одна из причин — теория разработки компиляторов. Известно, что <a href="http://blog.sjinks.pro/tag/html/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  HTML">HTML</a> — это грамматика второго типа в иерархии Хомского (контекстно-свободная грамматика), а регулярные выражения — грамматика третьего типа (регулярная грамматика). Грамматика второго типа является более сложной, нежели грамматика третьего типа. Как следствие, описать более простой грамматикой то, что соответствует более сложной, очень трудно (вряд ли возможно на 100%, но это моё мнение).</p>
<p>Что плохо, среди <a href="http://codex.wordpress.org/Automated_Testing">тестов WordPress</a> я не нашёл тестов для KSES. Что может означать, что, вероятно, никто из разработчиков не строил и не проверял граф путей в KSES; как следствие, не гарантии, что при граничных условиях всё будет работать нормально.</p>
<p>Другая причина, по которой я не люблю регулярные выражения — это скорость: особой производительностью они не отличаются. Хотя с другой стороны, объёмы проверяемого текста не так велики, чтобы KSES оказывал существенное влияние на <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a>.</p>
<p>Каковы альтернативы? <a href="http://htmlpurifier.org/comparison">Обзор</a>.</p>
<p>На <em>мой</em> взгляд, самая удобная альтернатива — использование DOM XML и работа с полученным деревом. Тем более, что в <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> есть соответствующая поддержка. А парсер на C в любом случае быстрее парсера на <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>.</p>
<p>Парсер DOM XML в PHP позволяет работать даже с некорректным HTML. Что означает, что он берёт на себя решение проблемы с неправильно закрытыми или незакрытыми тэгами. Парсер понимает HTML entities и преобразует их в нормальный текст. Что означает, что не нужно возиться с разными форматами записи entities и переводить их к одному виду (чему в KSES уделено не мало кода). И так далее.</p>
<p>Для проверки некоторых идей я написал небольшой класс, который делает <em>почти</em> то же самое, что и KSES, только иначе <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  Я ни в коем случае не рассматриваю его как замену KSES.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p89410">
        <div class="code php" id="p894code10">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw2">class</span> Xex<br />
&nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$protocols</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$tags</span> &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$css</span> &nbsp; &nbsp; &nbsp; <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$strip_comments</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$strip_script_text</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$strip_style_text</span> &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$script_text</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$style_text</span> &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="re0">$trim_text</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> __construct<span class="br0">&#40;</span><span class="kw1">array</span> <span class="re0">$tags</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="kw1">array</span> <span class="re0">$protocols</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="sy0">,</span> <span class="kw1">array</span> <span class="re0">$css</span> <span class="sy0">=</span> <span class="kw4">null</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">null</span> <span class="sy0">!==</span> <span class="re0">$tags</span><span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">tags</span> <span class="sy0">=</span> <span class="re0">$tags</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">null</span> <span class="sy0">!==</span> <span class="re0">$protocols</span><span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">protocols</span> <span class="sy0">=</span> <span class="kw3">array_combine</span><span class="br0">&#40;</span><span class="re0">$protocols</span><span class="sy0">,</span> <span class="re0">$protocols</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">null</span> <span class="sy0">!==</span> <span class="re0">$css</span><span class="br0">&#41;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">css</span> <span class="sy0">=</span> <span class="kw3">array_combine</span><span class="br0">&#40;</span><span class="re0">$css</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">function</span> checkProtocols<span class="br0">&#40;</span><span class="re0">$str</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es1">\r</span>&quot;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\t</span>&quot;</span><span class="sy0">,</span> <span class="st0">&quot;&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$str</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">':'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="sy0">,</span> 2<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="co1">// See http://tools.ietf.org/html/rfc3986#section-3.1</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">preg_match</span><span class="br0">&#40;</span><span class="st_h">'/^[a-z][a-z0-9+.-]*$/'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="sy0">&amp;&amp;</span> <span class="sy0">!</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">protocols</span><span class="br0">&#91;</span><span class="re0">$s</span><span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$str</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">function</span> sanitizeCss<span class="br0">&#40;</span><span class="re0">$css</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">,</span><span class="st0">&quot;<span class="es1">\r</span>&quot;</span><span class="sy0">,</span><span class="st0">&quot;<span class="es1">\t</span>&quot;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">preg_match</span><span class="br0">&#40;</span><span class="st_h">'![\\(&amp;=}]|/\\*!'</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$arr</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">';'</span><span class="sy0">,</span> <span class="kw3">trim</span><span class="br0">&#40;</span><span class="re0">$css</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">=</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$arr</span> <span class="kw1">as</span> <span class="re0">$x</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$x</span> <span class="sy0">=</span> <span class="kw3">trim</span><span class="br0">&#40;</span><span class="re0">$x</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$x</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$found</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">false</span> <span class="sy0">===</span> <span class="kw3">strpos</span><span class="br0">&#40;</span><span class="re0">$x</span><span class="sy0">,</span> <span class="st_h">':'</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$found</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$parts</span> <span class="sy0">=</span> <span class="kw3">explode</span><span class="br0">&#40;</span><span class="st_h">':'</span><span class="sy0">,</span> <span class="re0">$x</span><span class="sy0">,</span> 2<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">css</span><span class="br0">&#91;</span><span class="kw3">rtrim</span><span class="br0">&#40;</span><span class="re0">$parts</span><span class="br0">&#91;</span>0<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$found</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$found</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">.=</span> <span class="re0">$x</span> <span class="sy0">.</span> <span class="st_h">';'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$css</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">protected</span> <span class="kw2">function</span> parseDOM<span class="br0">&#40;</span>DOMNode <span class="re0">$el</span><span class="sy0">,</span> DOMNode <span class="re0">$new</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">nodeType</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_ELEMENT_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$prefix</span> <span class="sy0">=</span> <span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> ? <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> <span class="sy0">.</span> <span class="st_h">':'</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$tag</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="re0">$prefix</span> <span class="sy0">.</span> <span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">tagName</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">tags</span><span class="br0">&#91;</span><span class="re0">$tag</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span> <span class="sy0">=</span> <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">false</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">hasAttributes</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$attrs</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">tags</span><span class="br0">&#91;</span><span class="re0">$tag</span><span class="br0">&#93;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">attributes</span> <span class="kw1">as</span> <span class="re0">$a</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="kw1">isset</span><span class="br0">&#40;</span><span class="re0">$attrs</span><span class="br0">&#91;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span><span class="sy0">-&gt;</span><span class="me1">removeAttribute</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="st_h">'style'</span> <span class="sy0">==</span> <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$css</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">sanitizeCss</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$css</span> <span class="sy0">!=</span> <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span><span class="sy0">-&gt;</span><span class="me1">setAttribute</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="sy0">,</span> <span class="re0">$css</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="kw3">in_array</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="sy0">,</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="st_h">'xmlns'</span><span class="sy0">,</span> <span class="st_h">'profile'</span><span class="sy0">,</span> <span class="st_h">'href'</span><span class="sy0">,</span> <span class="st_h">'src'</span><span class="sy0">,</span> <span class="st_h">'cite'</span><span class="sy0">,</span> <span class="st_h">'classid'</span><span class="sy0">,</span> <span class="st_h">'codebase'</span><span class="sy0">,</span> <span class="st_h">'data'</span><span class="sy0">,</span> <span class="st_h">'usemap'</span><span class="sy0">,</span> <span class="st_h">'longdesc'</span><span class="sy0">,</span> <span class="st_h">'action'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">checkProtocols</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$s</span> <span class="sy0">!=</span> <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">value</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span><span class="sy0">-&gt;</span><span class="me1">setAttribute</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">name</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$tag</span> <span class="sy0">==</span> <span class="st_h">'script'</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">strip_script_text</span> <span class="sy0">||</span> <span class="re0">$tag</span> <span class="sy0">==</span> <span class="st_h">'style'</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">strip_style_text</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$n</span> <span class="sy0">=</span> <span class="re0">$new</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">hasChildNodes</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">foreach</span> <span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">childNodes</span> <span class="kw1">as</span> <span class="re0">$e</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">parseDOM</span><span class="br0">&#40;</span><span class="re0">$e</span><span class="sy0">,</span> <span class="re0">$n</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_TEXT_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">trim_text</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="kw2">new</span> DOMText<span class="br0">&#40;</span><span class="kw3">trim</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">wholeText</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_CDATA_SECTION_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> XML_COMMENT_NODE<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$parent</span> <span class="sy0">=</span> <span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">parentNode</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$parent</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">tagName</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$prefix</span> <span class="sy0">=</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> ? <span class="br0">&#40;</span><span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">prefix</span> <span class="sy0">.</span> <span class="st_h">':'</span><span class="br0">&#41;</span> <span class="sy0">:</span> <span class="st_h">''</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$tag</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="re0">$prefix</span> <span class="sy0">.</span> <span class="re0">$parent</span><span class="sy0">-&gt;</span><span class="me1">tagName</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="st_h">'style'</span> <span class="sy0">==</span> <span class="re0">$tag</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">style_text</span> <span class="sy0">||</span> <span class="st_h">'script'</span> <span class="sy0">==</span> <span class="re0">$tag</span> <span class="sy0">&amp;&amp;</span> <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">script_text</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="kw2">new</span> DOMText<span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">data</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="sy0">!</span><span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">strip_comments</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="re0">$el</span><span class="sy0">-&gt;</span><span class="me1">cloneNode</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span><span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> sanitize<span class="br0">&#40;</span><span class="re0">$s</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span> <span class="sy0">=</span> <span class="kw2">new</span> DOMDocument<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">recover</span> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">strictErrorChecking</span> <span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">substituteEntities</span> &nbsp;<span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">resolveExternals</span> &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">formatOutput</span> &nbsp; &nbsp; &nbsp; &nbsp;<span class="sy0">=</span> <span class="kw4">false</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$old</span> <span class="sy0">=</span> <span class="kw3">libxml_use_internal_errors</span><span class="br0">&#40;</span><span class="kw4">true</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">str_replace</span><span class="br0">&#40;</span><span class="kw3">chr</span><span class="br0">&#40;</span><span class="nu0">0</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st_h">''</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">preg_replace</span><span class="br0">&#40;</span><span class="st_h">'!&lt;([^a-z\\?\\!/])!i'</span><span class="sy0">,</span> <span class="st_h">'&amp;lt;$1'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="kw3">preg_replace</span><span class="br0">&#40;</span><span class="st_h">'!&lt;((?:[\\?\\!/]\\s*)?[a-z][^&gt;]*)(?=&lt;)!i'</span><span class="sy0">,</span> <span class="st_h">'&amp;lt;$1'</span><span class="sy0">,</span> <span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">@</span><span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">loadHTML</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">libxml_use_internal_errors</span><span class="br0">&#40;</span><span class="re0">$old</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span> <span class="sy0">=</span> <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">createDocumentFragment</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">appendChild</span><span class="br0">&#40;</span><span class="kw2">new</span> DOMElement<span class="br0">&#40;</span><span class="st_h">'wrap'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$this</span><span class="sy0">-&gt;</span><span class="me1">parseDOM</span><span class="br0">&#40;</span><span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">documentElement</span><span class="sy0">,</span> <span class="re0">$new</span><span class="sy0">-&gt;</span><span class="me1">firstChild</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">replaceChild</span><span class="br0">&#40;</span><span class="re0">$new</span><span class="sy0">,</span> <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">documentElement</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$s</span> <span class="sy0">=</span> <span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">saveXML</span><span class="br0">&#40;</span><span class="re0">$dom</span><span class="sy0">-&gt;</span><span class="me1">documentElement</span><span class="sy0">,</span> LIBXML_NOEMPTYTAG<span class="br0">&#41;</span><span class="sy0">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">substr</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="sy0">,</span> <span class="kw3">strpos</span><span class="br0">&#40;</span><span class="re0">$s</span><span class="sy0">,</span> <span class="st_h">'&lt;wrap&gt;'</span><span class="br0">&#41;</span> <span class="sy0">+</span> 6<span class="sy0">,</span> <span class="sy0">-</span>7<span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>Менее 200 строк против почти полутора тысяч.</p>
<p>На 45-килобайтном документе DOM быстрее KSES от 5 до 9 раз.<br />
На 90-килобайтном документе DOM быстрее KSES от 6 до 9 раз.<br />
На 180-килобайтном документе DOM быстрее KSES от 9 до 10 раз.</p>
<p>Производительность зависит от количества тэгов и стилей (разбор стилей реализован практически одинаково). Например, на домашней странице Google XEX может опережать KSES в 25 раз; если же соединить домашнюю страницу Google саму с собой 4 раза, разница во времени сокращается.</p>
<p>На домашней странице WordPress разница в 7 раз.</p>
<p>На <a href="http://blog.sjinks.pro/test/accordion/accordion1.html">этой странице</a> разница в 4 раза.</p>
<p>Всё-таки KSES очень медленный…</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/894-kses-wordpress-could-it-be-simplier/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>Блокировки транзакций InnoDB при удалении данных из таблицы</title>
		<link>http://blog.sjinks.pro/mysql/889-lock-wait-timeout-exceeded-try-restarting-transaction/</link>
		<comments>http://blog.sjinks.pro/mysql/889-lock-wait-timeout-exceeded-try-restarting-transaction/#comments</comments>
		<pubDate>Sat, 05 Feb 2011 16:01:16 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[InnoDB]]></category>
		<category><![CDATA[оптимизация]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=889</guid>
		<description><![CDATA[Lock wait timeout exceeded; try restarting transaction Ситуация: есть несколько физических почтовых серверов (PowerMTA), отсылающих более четырёх миллионов сообщений в сутки. Есть виртуальный сервер базы данных (причём не очень мощный), на котором крутится MySQL с InnoDB; в базу данных пишутся логи доставки/не доставки сообщений и ведётся статистика по IP-адресам, VMTA и доменам. Попутно выполняется классификация и [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/mysql/889-lock-wait-timeout-exceeded-try-restarting-transaction/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Lock wait timeout exceeded; try restarting transaction</em></h2>
<p>Ситуация: есть несколько физических почтовых серверов (PowerMTA), отсылающих более четырёх миллионов сообщений в сутки. Есть виртуальный сервер базы данных (причём не очень мощный), на котором крутится <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a> с <a href="http://blog.sjinks.pro/tag/innodb/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  InnoDB">InnoDB</a>; в базу данных пишутся логи доставки/не доставки сообщений и ведётся статистика по IP-адресам, VMTA и доменам. Попутно выполняется классификация и анализ hard и soft bounces. База за день увеличивается примерно на 5 гигабайт. Часть логов недельной давности удаляется.<span id="more-889"></span></p>
<p>Так как с базой (на запись) работает несколько клиентов, структура таблиц/индексы выбраны таким образом, чтобы обеспечить максимальную скорость добавления записей и минимум блокировок.</p>
<p>Проблема возникла с ведением статистики.</p>
<p>Есть таблица такой структуры:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p88914">
        <div class="code mysql" id="p889code14">
<span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="kw15">log</span> <span class="br0">&#40;</span><br />
&nbsp; &nbsp; id <span class="kw4">BIGINT</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span> <span class="kw1">PRIMARY KEY</span> <span class="kw6">AUTO_INCREMENT</span><span class="sy2">,</span><br />
&nbsp; &nbsp; ymd <span class="kw4">INTEGER</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; domain <span class="kw4">VARCHAR</span><span class="br0">&#40;</span>255<span class="br0">&#41;</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; vmta <span class="kw4">VARCHAR</span><span class="br0">&#40;</span>255<span class="br0">&#41;</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; ip <span class="kw4">VARCHAR</span><span class="br0">&#40;</span>45<span class="br0">&#41;</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; deliveries <span class="kw4">TINYINT</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; bounces <span class="kw4">TINYINT</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; transients <span class="kw4">TINYINT</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><span class="sy2">,</span><br />
&nbsp; &nbsp; pmta_bounces <span class="kw4">TINYINT</span> <span class="kw6">UNSIGNED</span> <span class="kw10">NOT</span> <span class="kw3">NULL</span><br />
<span class="br0">&#41;</span> <span class="kw1">ENGINE</span><span class="sy1">=</span><span class="kw1">InnoDB</span> <span class="kw2">DEFAULT</span> <span class="kw7">CHARSET</span><span class="sy1">=</span>utf8<span class="sy2">;</span>
        </div>
    </div>
</div>

<p>В таблицу заносятся данные о доставке сообщений — выполняется это триггерами post insert: при доставке сообщения в таблицу заносится запись <span class="codebox"><code class="mysql"><span class="br0">&#40;</span><span class="kw3">NULL</span><span class="sy2">,</span> <span class="kw17">DATE_FORMAT</span><span class="br0">&#40;</span><span class="kw17">NOW</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy2">,</span> <span class="st0">&quot;<span class="es1">%</span>Y<span class="es1">%</span>m<span class="es1">%</span>d&quot;</span><span class="br0">&#41;</span><span class="sy2">,</span> domain<span class="sy2">,</span> vmta<span class="sy2">,</span> ip<span class="sy2">,</span> <span class="nu0">1</span><span class="sy2">,</span> <span class="nu0">0</span><span class="sy2">,</span> <span class="nu0">0</span><span class="sy2">,</span> <span class="nu0">0</span><span class="sy2">,</span> <span class="nu0">0</span><span class="br0">&#41;</span></code></span>, при получении hard bounce — <span class="codebox"><code class="mysql"><span class="br0">&#40;</span><span class="kw3">NULL</span><span class="sy2">,</span> <span class="kw17">DATE_FORMAT</span><span class="br0">&#40;</span><span class="kw17">NOW</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy2">,</span> <span class="st0">&quot;<span class="es1">%</span>Y<span class="es1">%</span>m<span class="es1">%</span>d&quot;</span><span class="br0">&#41;</span><span class="sy2">,</span> domain<span class="sy2">,</span> vmta<span class="sy2">,</span> ip<span class="sy2">,</span> <span class="nu0">0</span><span class="sy2">,</span> <span class="nu0">1</span><span class="sy2">,</span> <span class="nu0">0</span><span class="sy2">,</span> <span class="nu0">0</span><span class="sy2">,</span> <span class="nu0">0</span><span class="br0">&#41;</span></code></span> — всё это выполняется довольно быстро, жалоб нет.</p>
<p>Проблемы начинаются при обработке данного лога. Что нужно сделать: подсчитать SUM(deliveries), SUM(bounces), SUM(transients), SUM(pmta_bounces) для каждой четвёрки (ymd, domain, vmta, ip). Данная операция выполняется каждые десять минут. Обработанные данные из таблицы log нужно удалить.</p>
<p>В терминах SQL это выглядит примерно так:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p88915">
        <div class="code mysql" id="p889code15">
<span class="kw1">CREATE</span> <span class="kw1">PROCEDURE</span> populate_stats_daily<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
<span class="kw1">BEGIN</span><br />
&nbsp; &nbsp; <span class="kw1">DECLARE</span> max_id <span class="kw4">BIGINT</span> <span class="kw6">UNSIGNED</span><span class="sy2">;</span><br />
<br />
&nbsp; &nbsp; <span class="kw1">START</span> <span class="kw1">TRANSACTION</span><span class="sy2">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">SELECT</span> <span class="kw22">MAX</span><span class="br0">&#40;</span>id<span class="br0">&#41;</span> <span class="kw1">INTO</span> max_id <span class="kw1">FROM</span> <span class="kw15">log</span><span class="sy2">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">INSERT</span> <span class="kw1">INTO</span> stats_daily <span class="br0">&#40;</span>ymd<span class="sy2">,</span> domain<span class="sy2">,</span> vmta<span class="sy2">,</span> ip<span class="sy2">,</span> deliveries<span class="sy2">,</span> bounces<span class="sy2">,</span> transients<span class="sy2">,</span> pmta_bounces<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">SELECT</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ymd<span class="sy2">,</span> domain<span class="sy2">,</span> vmta<span class="sy2">,</span> ip<span class="sy2">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw22">SUM</span><span class="br0">&#40;</span>deliveries<span class="br0">&#41;</span> <span class="kw1">AS</span> deliveries<span class="sy2">,</span> <span class="kw22">SUM</span><span class="br0">&#40;</span>bounces<span class="br0">&#41;</span> <span class="kw1">AS</span> bounces<span class="sy2">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw22">SUM</span><span class="br0">&#40;</span>transients<span class="br0">&#41;</span> <span class="kw1">AS</span> transients<span class="sy2">,</span> <span class="kw22">SUM</span><span class="br0">&#40;</span>pmta_bounces<span class="br0">&#41;</span> <span class="kw1">AS</span> pmta_bounces<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">FROM</span> <span class="kw15">log</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">WHERE</span> id <span class="sy1">&lt;=</span> max_id<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">GROUP BY</span> ymd<span class="sy2">,</span> domain<span class="sy2">,</span> vmta<span class="sy2">,</span> ip<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">ORDER BY</span> <span class="kw3">NULL</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">ON</span> <span class="kw1">DUPLICATE KEY</span> <span class="kw1">UPDATE</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; deliveries &nbsp; <span class="sy1">=</span> deliveries <span class="sy1">+</span> <span class="kw1">VALUES</span><span class="br0">&#40;</span>deliveries<span class="br0">&#41;</span><span class="sy2">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bounces &nbsp; &nbsp; &nbsp;<span class="sy1">=</span> bounces <span class="sy1">+</span> <span class="kw1">VALUES</span><span class="br0">&#40;</span>bounces<span class="br0">&#41;</span><span class="sy2">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; transients &nbsp; <span class="sy1">=</span> transients <span class="sy1">+</span> <span class="kw1">VALUES</span><span class="br0">&#40;</span>transients<span class="br0">&#41;</span><span class="sy2">,</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pmta_bounces <span class="sy1">=</span> pmta_bounces <span class="sy1">+</span> <span class="kw1">VALUES</span><span class="br0">&#40;</span>pmta_bounces<span class="br0">&#41;</span><span class="sy2">;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">DELETE</span> <span class="kw1">FROM</span> <span class="kw15">log</span> <span class="kw1">WHERE</span> id <span class="sy1">&lt;=</span> max_id<span class="sy2">;</span><br />
&nbsp; &nbsp; <span class="kw1">COMMIT</span><span class="sy2">;</span><br />
<span class="kw12">END</span>
        </div>
    </div>
</div>

<p>Проблема наступает при выполнении оператора <code>DELETE</code>: <code>SHOW PROCESSLIST</code> показывает состояние <code>Updating</code> минуты полторы, после чего в <a href="http://blog.sjinks.pro/tag/log/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  лог">лог</a> пишется печально известное сообщение <strong>Lock wait timeout exceeded; try restarting transaction</strong> и транзакция откатывается. При этом количество записей в таблице <code>log</code> всего лишь порядка 80,000.</p>
<p>В принципе, проблема с <code>DELETE</code> <a href="http://www.google.ru/search?q=InnoDB+slow+delete">давно известна</a>: в InnoDB удаление строк весьма тормозное. По всей видимости, это усугубляется тем, что в таблицу постоянно идёт запись новых данных. Руководство пользователя <a href="http://dev.mysql.com/doc/refman/5.1/en/innodb-locks-set.html">объясняет</a> суть проблемы.</p>
<p>А решение таково: заводим дополнительную колонку в таблице (<code>processed</code>) и создаём по ней индекс. <code>DELETE FROM log WHERE id <= max_id</code> заменяем на <code>UPDATE log SET processed = 1 WHERE id <= max_id</code>, что выполняется гораздо быстрее. Затем заводим еще одну транзакцию, в которой удаляем строки с <code>processed = 1</code>.</p>
<p>Но в один заход все строки удалить не получится, поэтому придётся идти на хитрость:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p88916">
        <div class="code mysql" id="p889code16">
<span class="kw1">BEGIN</span><br />
&nbsp; &nbsp; <span class="kw1">DECLARE</span> cnt <span class="kw4">BIGINT</span> <span class="kw6">UNSIGNED</span><span class="sy2">;</span><br />
<br />
<span class="coMULTI">/* ... */</span><br />
<br />
&nbsp; &nbsp; <span class="kw13">REPEAT</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">START</span> <span class="kw1">TRANSACTION</span><span class="sy2">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">DELETE</span> <span class="kw1">FROM</span> <span class="kw15">log</span> <span class="kw1">WHERE</span> processed <span class="sy1">=</span> 1 <span class="kw1">LIMIT</span> <span class="nu0">1000</span><span class="sy2">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">SELECT</span> <span class="kw23">ROW_COUNT</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="kw1">INTO</span> cnt<span class="sy2">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">COMMIT</span><span class="sy2">;</span><br />
&nbsp; &nbsp; UNTIL cnt <span class="sy1">=</span> 0 <span class="kw12">END</span> <span class="kw13">REPEAT</span><span class="sy2">;</span><br />
<span class="kw12">END</span>
        </div>
    </div>
</div>

<p>Смысл в том, что удаление производится небольшими кусками (что будет относительно быстро); каждое удаление выполняется в своей транзакции (в случае блокировки транзакции в хвосте таблицы большая часть записей будет удалена, что не так плохо).</p>
<p>Вполне возможно, что можно обойтись без дополнительной колонки и использовать <code>REPEAT … END REPEAT</code> с <code>DELETE FROM log WHERE id <= max_id</code>, но текущий вариант работает, кушать не просит, блокировок не создаёт. А наше основное правило — <span title="if it ain't broke, don't fix it">si fractum non sit, noli id reficere</span>.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/mysql/889-lock-wait-timeout-exceeded-try-restarting-transaction/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/mysql/889-lock-wait-timeout-exceeded-try-restarting-transaction/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>WordPress: кэширование средствами nginx</title>
		<link>http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/</link>
		<comments>http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/#comments</comments>
		<pubDate>Fri, 10 Dec 2010 12:08:15 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[nginx]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[кэш]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=877</guid>
		<description><![CDATA[Уменьшение потребления ресурсов во много раз Много было сказано про кэширование в WordPress… Сегодня я хочу рассказать о действительно эффективном методе, позволяющем сильно снизить нагрузку. Метод основан на использовании кэша FastCGI web-сервера nginx. Идея состоит в генерации статических страниц и отдачи их пользователям, не имеющим cookie комментатора. Зарегистрированным пользователям, а также комментаторам всегда отдаётся свежая [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Уменьшение потребления ресурсов во много раз</em></h2>
<p>Много было сказано про <a href="http://blog.sjinks.pro/?s=WordPress%20cache">кэширование в WordPress</a>… Сегодня я хочу рассказать о действительно эффективном методе, позволяющем сильно снизить нагрузку.</p>
<p>Метод основан на использовании кэша <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a> web-сервера <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a>.</p>
<p>Идея состоит в генерации статических страниц и отдачи их пользователям, не имеющим cookie комментатора. Зарегистрированным пользователям, а также комментаторам всегда отдаётся свежая страница. Так как читателей, ни разу не оставлявших комментарий, как правило, гораздо больше, чем комментаторов, то подобный использование кэша позволяет значительно снизить нагрузку на <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a>/<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>. Знакомые с принципом работы <a href="http://blog.sjinks.pro/tag/wp-super-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WP Super Cache">WP Super Cache</a> заметят, что WPSC использует тот же принцип работы.<span id="more-877"></span></p>
<p>В чем же преимущество перекладывания работы на Web-сервер (nginx)?</p>
<ol>
<li>PHP — интерпретируемый язык. Как следствие, аналогичный код на компилируемом языке будет во много раз быстрее.</li>
<li>WordPress во многом bloatware <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  От момента начала загрузки страницы до окончания выполнения стадии <code>init</code> выполняется очень много «лишнего» кода.</li>
<li>В зависимости от нагрузки на сервер от запроса страницы до выполнения PHP-кода может пройти некоторое время: всё зависит от загруженности PHP (если все дочерние процессы PHP заняты обработкой запроса, новому запросу придётся ждать освобождения одного из процессов. Если за приемлемое время ни один процесс не освободился, пользователь видит сообщение о печально знаменитой ошибке 504).</li>
<li>Когда обслуживанием кэша занимается web-сервер, шансы на возникновение <a href="http://blog.sjinks.pro/wordpress/521-wp-super-cache-under-high-load/">подобной ситуации</a></li>
 (когда даже автор не может понять, в чём дело) значительно снижаются: реализация синхронизации/блокировок средствами PHP — неблагодарное дело.
</ol>
<p>Теперь переходим от теории к практике.</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p87719">
        <div class="code nginx" id="p877code19">
<ol class="nginx" style="font-family:monospace;"><li class="li1"><div class="de1"><span class="kw1">fastcgi_cache_path</span> /var/lib/nginx/myblog levels=2 keys_zone=myblog:10m max_size=512m inactive=20m;</div></li>
<li class="li1"><div class="de1"><span class="kw1">server</span> {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">server_name</span> example.com;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">root</span> /path/to/blog;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> ($http_cookie ~* <span class="st0">&quot;comment_author_|wordpress_(?!test_cookie)|wp-postpass_&quot;</span> ) {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">set</span> $do_not_cache <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; fastcgi_cache_bypass $do_not_cache;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; fastcgi_no_cache $do_not_cache;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_pass_header</span> Cookie;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache</span> myblog;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_key</span> $request_method|$host|$request_uri;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_valid</span> 301 8h;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_valid</span> 404 1h;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">fastcgi_cache_valid</span> 200 15m;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">if</span> ($http_user_agent !~ FeedBurner) {</div></li>
<li class="li1"><div class="de1"><span class="co1"># Здесь идут перенаправления для FeedBurner</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">error_page</span> 404 = @wordpress;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">log_not_found</span> <span class="kw2">off</span>;</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ^~ /files/ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">rewrite</span> /files/(.+) /wp-includes/ms-files.php?file=$1 last;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ~ ^/(wp-admin/.*\.php|wp-login\.php|wp-register\.php|(feed|comment/feed)(/.*)?)$ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">try_files</span> $uri @wordpress;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">set</span> $do_not_cache <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; fastcgi_cache_bypass <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; fastcgi_no_cache <span class="nu0">1</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> unix:/dev/shm/php-fcgi.sock;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME $document_root$fastcgi_script_name;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> @wordpress {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_NAME /<span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME $document_root/<span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> unix:/dev/shm/php-fcgi.sock;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> ($do_not_cache != <span class="st0">&quot;1&quot;</span>) {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">add_header</span> Vary Cookie;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ~ \.php$ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">include</span> /etc/nginx/fastcgi_params;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_index</span> <span class="kw1">index</span>.php;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_param</span> SCRIPT_FILENAME $document_root$fastcgi_script_name;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">try_files</span> $uri @wordpress;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">fastcgi_pass</span> unix:/dev/shm/php-fcgi.sock;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> ($do_not_cache != <span class="st0">&quot;1&quot;</span>) {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">add_header</span> Vary Cookie;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="kw1">location</span> ^~ /blogs.dir/ {</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">internal</span>;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">root</span> /path/to/blog/wp-content/;</div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; }</div></li>
<li class="li1"><div class="de1">}</div></li>
</ol>
        </div>
    </div>
</div>

<p>Документация по использованию FastCGI в nginx приведена <a href="http://sysoev.ru/nginx/docs/http/ngx_http_fastcgi_module.html">здесь</a>, поэтому я не буду подробно останавливаться на том, что конкретно каждая директива делает.</p>
<p>Основная магия происходит в строка 8—10: здесь определяются условия, при которых отдаётся свежая страница. В данном случае проверяется наличие авторизационных cookie и cookie комментатора. Важно, чтобы в случае отказа от кэширования переменная $<code>do_not_cache</code> устанавливалась в 1.</p>
<p>Строка 16 задаёт ключ, по которому страница доступна в кэше. В ключе присутствует <code>$request_method</code>, чтобы различать запросы GET и HEAD (для HEAD данные не возвращаются, только заголовки).</p>
<p>Строки 17—19 задают время жизни кэша в зависимости от кода ответа. Чем больше время жизни, тем реже будет обновляться информация для незарегистрированных пользователей.</p>
<p>В строке 32 задаётся маска для страниц, которые не должны кэшироваться (например, админка, страницы логина и регистрации, фиды).</p>
<p>Так как содержимое страницы <em>может</em> отличаться в зависимости от cookie пользователя, в строках 49 и 59 для закэшированных страниц принудительно выставляется заголовок <code>Vary: Cache</code>. Если используются другие правила (например, фильтрация по User-Agent), нужно добавлять соответствующее правило.</p>
<p>Строки 21—23: подробнее описано в статье <strong>«<a href="http://blog.sjinks.pro/wordpress/691-redirect-rss-feeds-to-feedburner-with-nginx/">Перенаправление RSS в WordPress на FeedBurner для nginx</a>»</strong></p>
<p>Строки 28—30, 63—66 подробнее описаны в статье <strong>«<a href="http://blog.sjinks.pro/wordpress/874-wpms-nginx-accel-redirect/">WordPress MultiSite, nginx и X-Accel-Redirect</a>»</strong></p>
<p>Вроде бы ничего не забыл. Теперь о том, какую <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a> мы получаем:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p87720">
        <div class="code text" id="p877code20">
$ ab -n 10000 -c 100 http://blog.sjinks.pro/<br />
Server Software: &nbsp; &nbsp; &nbsp; &nbsp;nginx<br />
Server Hostname: &nbsp; &nbsp; &nbsp; &nbsp;blog.sjinks.pro<br />
Server Port: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;80<br />
<br />
Document Path: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/<br />
Document Length: &nbsp; &nbsp; &nbsp; &nbsp;50294 bytes<br />
<br />
Concurrency Level: &nbsp; &nbsp; &nbsp;100<br />
Time taken for tests: &nbsp; 46.925 seconds<br />
Complete requests: &nbsp; &nbsp; &nbsp;10000<br />
Failed requests: &nbsp; &nbsp; &nbsp; &nbsp;0<br />
Write errors: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0<br />
Total transferred: &nbsp; &nbsp; &nbsp;504940000 bytes<br />
HTML transferred: &nbsp; &nbsp; &nbsp; 502940000 bytes<br />
Requests per second: &nbsp; &nbsp;213.10 [#/sec] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 469.254 [ms] (mean)<br />
Time per request: &nbsp; &nbsp; &nbsp; 4.693 [ms] (mean, across all concurrent requests)<br />
Transfer rate: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;10508.28 [Kbytes/sec] received<br />
<br />
Connection Times (ms)<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; min &nbsp;mean[+/-sd] median &nbsp; max<br />
Connect: &nbsp; &nbsp; &nbsp; 16 &nbsp; 94 &nbsp;76.9 &nbsp; &nbsp; 94 &nbsp; &nbsp;3125<br />
Processing: &nbsp; 118 &nbsp;373 &nbsp;81.7 &nbsp; &nbsp;360 &nbsp; &nbsp;1334<br />
Waiting: &nbsp; &nbsp; &nbsp; 17 &nbsp; 69 &nbsp;38.5 &nbsp; &nbsp; 57 &nbsp; &nbsp; 422<br />
Total: &nbsp; &nbsp; &nbsp; &nbsp;156 &nbsp;467 105.0 &nbsp; &nbsp;445 &nbsp; &nbsp;3535<br />
<br />
Percentage of the requests served within a certain time (ms)<br />
&nbsp; 50% &nbsp; &nbsp;445<br />
&nbsp; 66% &nbsp; &nbsp;454<br />
&nbsp; 75% &nbsp; &nbsp;471<br />
&nbsp; 80% &nbsp; &nbsp;494<br />
&nbsp; 90% &nbsp; &nbsp;541<br />
&nbsp; 95% &nbsp; &nbsp;589<br />
&nbsp; 98% &nbsp; &nbsp;655<br />
&nbsp; 99% &nbsp; &nbsp;768<br />
&nbsp;100% &nbsp; 3535 (longest request)
        </div>
    </div>
</div>

<p>Сервер зафлудили 10,000 запросами в 100 <strong>параллельных</strong> потоков. Сервер выдал практически полгигабайта за 47 секунд; в среднем сервер обрабатывал <strong>213 запросов в секунду</strong>, при этом <strong>99% запросов были обработаны за 768 мс</strong> (при том, что на сервере несколько сайтов в Alexa Top 100,000)! Нагрузка на сервер была минимальной (изменений Load Average замечено не было).</p>
<p><strong style="color: red">UPDATE:</strong> есть один небольшой нюанс: CAPTCHA. Если вы их используете, убедитесь, что они работают. Дело в том, что страница со статьёй будет отдаваться непосредственно из кэша nginx, PHP загружаться не будет. Поэтому если CAPTCHA полагается на использование сессии, она может работать неправильно. Здесь всё зависит от используемого плагина.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/877-wordpress-caching-with-nginx/feed/</wfw:commentRss>
		<slash:comments>61</slash:comments>
		</item>
		<item>
		<title>WP Super Cache vs MaxSite Cache: часть 2</title>
		<link>http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/</link>
		<comments>http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/#comments</comments>
		<pubDate>Sun, 13 Dec 2009 08:23:41 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[FastCGI]]></category>
		<category><![CDATA[MaxSite Cache]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[WP Super Cache]]></category>
		<category><![CDATA[кэш]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=725</guid>
		<description><![CDATA[Тест страничных кэшей на грамотно настроенном сервере Вторая часть статьи WP Super Cache vs MaxSite Cache. В предыдущей части я сравнивал поведение MaxSite Cache и WP Super Cache на тестовом VDS (512 MiB RAM, 10 GB HD, Intel Xeon X3320 (1 ядро), 2.5 GHz), на котором ни операционная система, ни программное обеспечение не были специально [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Тест страничных кэшей на грамотно настроенном сервере</em></h2>
<p><strong>Вторая часть статьи <a href="http://blog.sjinks.pro/wordpress/689-wp-super-cache-vs-maxsite-cache-part-1/">WP Super Cache vs MaxSite Cache</a></strong>.</p>
<p>В предыдущей части я сравнивал поведение <a href="http://blog.sjinks.pro/tag/maxsite-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MaxSite Cache">MaxSite Cache</a> и <a href="http://blog.sjinks.pro/tag/wp-super-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WP Super Cache">WP Super Cache</a> на тестовом VDS (512 MiB RAM, 10 GB HD, Intel Xeon X3320 (1 ядро), 2.5 GHz), на котором ни операционная система, ни программное обеспечение не были специально настроены — бралась конфигурация «из коробки» и тестировалась. Одним словом, «VDS абсолютного чайника».</p>
<p>В этой части изменилась только конфигурация программного обеспечения: сервер настраивался на максимальную <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a>.</p>
<p>В частности:</p>
<ul>
<li>отказ от Apache в пользу <a href="http://blog.sjinks.pro/tag/nginx/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  nginx">nginx</a> и от <code>mod_<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a>5</code> в пользу <code>php-fcgi</code> (количество <a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a>-процессов выбиралось таким образом, чтобы избежать использования файла подкачки);</li>
<li>смена ядра с <code>linux-image-server</code> на <code>linux-image-virtual</code>;</li>
<li>настройка <a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a>: отказ от <a href="http://blog.sjinks.pro/tag/innodb/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  InnoDB">InnoDB</a> (экономит примерно 100 МБ памяти), увеличение буфера ключей и т.п.;</li>
<li>установка и настройка xCache (я исходил из того, что далеко не все чувствуют себя комфортно при сборке программ из исходников, поэтому брал только готовое ПО);</li>
<li>настройка <span class="codebox"><code class="bash">iptables</code></span> для фильтрации пакетов.</li>
</ul>
<p><span id="more-725"></span></p>
<p>Методика тестирования осталась прежней: <a href="http://blog.sjinks.pro/linux/722-transform-sitemap-to-siege-url-list/">карта сайта преобразовывалась в список адресов</a>, на этот список натравливался <code>siege</code>, а я присматривал за сервером и вносил коррективы в конфигурацию ПО (да, с первого раза трудно всё настроить идеально).</p>
<p>Чтобы убедиться, что новая конфигурация <strong>не хуже</strong> старой, я полностью отключил кэширование и имитировал 50 одновременных посетителей в течение 15 минут. На момент выполнения теста у сервера было свободно 348.5 МиБ памяти.</p>
<table class="bordered" cellspacing="0" cellpadding="0" rules="all">
<thead>
<tr>
<th>&nbsp;</th>
<th><strong>Голый <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a></strong></th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Количество транзакций</th>
<td>4,825</td>
</tr>
<tr>
<th scope="row">Доступность сервера</th>
<td>99.98%</td>
</tr>
<tr>
<th scope="row">Объём данных, МБ</th>
<td>28.32</td>
</tr>
<tr>
<th scope="row">Среднее время ответа, с</th>
<td>9.23</td>
</tr>
<tr>
<th scope="row">Частота транзакций в секунду</th>
<td>5.36</td>
</tr>
<tr>
<th scope="row">Пропускная способность, МБ/с</th>
<td>0.03</td>
</tr>
<tr>
<th scope="row">Коэффициент параллельности</th>
<td>49.50</td>
</tr>
<tr>
<th scope="row">Максимальная длина транзакции, с</th>
<td>30.76</td>
</tr>
<tr>
<th scope="row">Минимальная длина транзакции, с</th>
<td>1.15</td>
</tr>
<tr>
<th scope="row">Максимальная загрузка процессора (system/user)</th>
<td>25.72%/68.39%</td>
</tr>
<tr>
<th scope="row">Load Average</th>
<td>40.81</td>
</tr>
<tr>
<th scope="row">Примерное потребление памяти, МиБ</th>
<td>414</td>
</tr>
</tbody>
</table>
<p>Данные загрузки/потребления памяти очень приблизительны. Хотя вряд ли пользователи станут ждать по 9 секунд загрузку страницы, радует, что сервер не ответил только на один запрос и не ушел в нокдаун. Простая экстраполяция показывает, что сервер выдержит примерно 463,000 обращения к PHP-страницам в сутки.</p>
<p>Мы убедились, что новая конфигурация вполне жизнеспособна (старой до неё, как до Китая в неудобной позе), переходим к тестированию плагинов.<br />
Тестирование проходило в 30 и 75 потоков. <strong>Я не разделял фазы построения и использования кэша</strong>.</p>
<table class="bordered" cellspacing="0" cellpadding="0" rules="all">
<thead>
<tr>
<th>&nbsp;</th>
<th><strong>MaxSite Cache</strong><br/>(30 потоков)</th>
<th><strong>MaxSite Cache</strong><br/>(75 потоков)</th>
<th><strong>WP Super Cache</strong><br/>(30 потоков, HALF ON)</th>
<th><strong>WP Super Cache</strong><br/>(30 потоков)</th>
<th><strong>WP Super Cache</strong><br/>(75 потоков)</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Количество транзакций</th>
<td>176,684</td>
<td>182,604</td>
<td>5,069</td>
<td>198,160</td>
<td>189,686</td>
</tr>
<tr>
<th scope="row">Объём данных, МБ</th>
<td>1,062.24</td>
<td>1,099.60</td>
<td>29.99</td>
<td>1,202.95</td>
<td>1,147.33</td>
</tr>
<tr>
<th scope="row">Среднее время ответа, с</th>
<td>0.13</td>
<td>0.34</td>
<td>5.30</td>
<td>0.10</td>
<td>0.29</td>
</tr>
<tr>
<th scope="row">Частота транзакций в секунду</th>
<td>196.36</td>
<td>203.00</td>
<td>5.64</td>
<td>220.20</td>
<td>210.95</td>
</tr>
<tr>
<th scope="row">Пропускная способность, МБ/с</th>
<td>1.18</td>
<td>1.32</td>
<td>0.03</td>
<td>1.34</td>
<td>1.28</td>
</tr>
<tr>
<th scope="row">Коэффициент параллельности</th>
<td>25.42</td>
<td>69.32</td>
<td>29.85</td>
<td>23.05</td>
<td>62.16</td>
</tr>
<tr>
<th scope="row">Максимальная длина транзакции, с</th>
<td>21.08</td>
<td>26.12</td>
<td>15.06</td>
<td>22.78</td>
<td>25.03</td>
</tr>
<tr>
<th scope="row">Минимальная длина транзакции, с</th>
<td>0.00</td>
<td>0.00</td>
<td>0.48</td>
<td>0.00</td>
<td>0.00</td>
</tr>
<tr>
<th scope="row">Load Average</th>
<td>1.8</td>
<td>2.2</td>
<td>30.1</td>
<td>1.3</td>
<td>1.65</td>
</tr>
</tbody>
</table>
<p><strong>Краткие выводы:</strong> на грамотно настроенном сервере лидирует WP Super Cache — и по скорости, и по создаваемой нагрузке. Это связано с тем, что задача по отдаче закэшированного контента переложена на web-сервер. Так как web-сервер справляется со статикой быстрее, чем с динамикой, в результате получаем рост производительности и снижение нагрузки.</p>
<p>Если по той или иной причине WP Super Cache не может работать в режиме Full On, то MaxSite Cache будет всё же предпочтительнее — ввиду своей простоты он обладает исключительным быстродействием.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/725-689-wp-super-cache-vs-maxsite-cache-part-2/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Оптимизация All in One SEO Pack</title>
		<link>http://blog.sjinks.pro/wordpress/patches/707-all-in-one-seo-pack-optimization/</link>
		<comments>http://blog.sjinks.pro/wordpress/patches/707-all-in-one-seo-pack-optimization/#comments</comments>
		<pubDate>Wed, 25 Nov 2009 05:35:33 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[Патчи]]></category>
		<category><![CDATA[All in One SEO Pack]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[патч]]></category>
		<category><![CDATA[плагин]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=707</guid>
		<description><![CDATA[Избавляемся от лишних запросов к базе данных Как оказалось, плагин All in One SEO Pack — один из основных источников запросов к базе данных на блогах с большим количеством страниц (page). Всё дело в том, что в All in One SEO Pack есть одна неотключаемая особенность: он пытается переписать все ссылки, которые выводятся через функцию wp_list_pages() [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/patches/707-all-in-one-seo-pack-optimization/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Избавляемся от лишних запросов к базе данных</em></h2>
<p>Как оказалось, <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a> <a href="http://blog.sjinks.pro/tag/all-in-one-seo-pack/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  All in One SEO Pack">All in One SEO Pack</a> — один из основных источников запросов к базе данных на блогах с большим количеством страниц (page). Всё дело в том, что в <a href="http://blog.sjinks.pro/tag/all-in-one-seo-pack/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  All in One SEO Pack">All in One SEO Pack</a> есть одна неотключаемая особенность: он пытается переписать все ссылки, которые выводятся через функцию <span class="codebox"><code class="php">wp_list_pages<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> (обычно эта функция вызывается из заголовка или подвала темы и используется для создания меню).</p>
<p>Вообще переписывание ссылок — это отдельная история, заслуживающая отдельной статьи. Если вкратце, то плагин берёт метаданные из поста и заменяет ими <code>title</code> и текст ссылки.</p>
<p><a href="http://static.sjinks.info/wp-content/uploads/2009/11/aiosp.png" rel="lightbox" title="All in One SEO Pack: Edit Page"><img src="http://static.sjinks.info/wp-content/uploads/2009/11/aiosp-300x115.png" alt="All in One SEO Pack: Edit Page" title="All in One SEO Pack: Edit Page" width="300" height="115" class="size-medium wp-image-708" /></a></p>
<p>Что характерно, если поле <code>Title Attribute</code> пустое, то All in One SEO Pack вообще затрёт <code>title</code> ссылки.</p>
<p>Проблема с запросами возникает из-за того, что All in One SEO Pack читает метаданные для каждой страницы, присутствующей в результате, который вернула функция <span class="codebox"><code class="php">wp_list_pages<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>. Если в меню тридцать страниц, то в результате получим тридцать лишних запросов к базе данных. Умножаем на количество показов страниц (страниц в широком смысле, а не в терминах <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a>) и получаем большую цифру.<span id="more-707"></span></p>
<p>К счастью, у проблемы есть решение. Я даже о нём писал — ещё год назад — <strong><a href="http://blog.sjinks.pro/wordpress/tips-and-tricks/349-secrets-of-update_postmeta_cache/">Секреты update_postmeta_cache(): Способ увеличения производительности при чтении метаданных записей</a></strong>.</p>
<p>В файле <code>all-in-one-seo-pack/all-in-one-seo-pack.<a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">php</a></code> нужно заменить несколько строчек.</p>
<ol>
<li>В районе 642 строки есть такой код:
          
<div class="codebox">
    <div class="the_code" style="" id="p70726">
        <div class="code php" id="p707code26">
<ol class="php" style="font-family:monospace;" start="642"><li class="li1"><div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$aioseop_options</span><span class="br0">&#91;</span><span class="st_h">'aiosp_enabled'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; add_action<span class="br0">&#40;</span><span class="st_h">'wp_list_pages'</span><span class="sy0">,</span> <span class="st_h">'aioseop_list_pages'</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1"><span class="br0">&#125;</span></div></li>
</ol>
        </div>
    </div>
</div>

<p>Нужно вместо <span class="codebox"><code class="php">add_action</code></span> поставить <span class="codebox"><code class="php">add_filter</code></span>:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p70727">
        <div class="code php" id="p707code27">
<ol class="php" style="font-family:monospace;" start="642"><li class="li1"><div class="de1"><span class="kw1">if</span><span class="br0">&#40;</span><span class="re0">$aioseop_options</span><span class="br0">&#91;</span><span class="st_h">'aiosp_enabled'</span><span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; add_filter<span class="br0">&#40;</span><span class="st_h">'wp_list_pages'</span><span class="sy0">,</span> <span class="st_h">'aioseop_list_pages'</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp;</div></li>
<li class="li1"><div class="de1"><span class="br0">&#125;</span></div></li>
</ol>
        </div>
    </div>
</div>

А если функциональность с переписыванием <code>title</code> ссылок вообще не нужна, то вместо замены слова проще закомментировать всю строку.</li>
<li>Затем нужно найти функцию <span class="codebox"><code class="php">aioseop_list_pages<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>:
          
<div class="codebox">
    <div class="the_code" style="" id="p70728">
        <div class="code php" id="p707code28">
<ol class="php" style="font-family:monospace;" start="665"><li class="li1"><div class="de1"><span class="co1">// The following two functions copied entirely and modified slightly from Sarah G's Page Menu Editor, http://wordpress.org/extend/plugins/page-menu-editor/</span></div></li>
<li class="li1"><div class="de1"><span class="kw2">function</span> aioseop_list_pages<span class="br0">&#40;</span><span class="re0">$content</span><span class="br0">&#41;</span><span class="br0">&#123;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$url</span> <span class="sy0">=</span> <span class="kw3">preg_replace</span><span class="br0">&#40;</span><span class="kw1">array</span><span class="br0">&#40;</span><span class="st_h">'/\//'</span><span class="sy0">,</span> <span class="st_h">'/\./'</span><span class="sy0">,</span> <span class="st_h">'/\-/'</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="st_h">'\/'</span><span class="sy0">,</span> <span class="st_h">'\.'</span><span class="sy0">,</span> <span class="st_h">'\-'</span><span class="br0">&#41;</span><span class="sy0">,</span> get_option<span class="br0">&#40;</span><span class="st_h">'siteurl'</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pattern</span> <span class="sy0">=</span> <span class="st_h">'/&lt;li class=&quot;page_item page-item-(\d+)([^\&quot;]*)&quot;&gt;&lt;a href=\&quot;([^\&quot;]+)&quot; title=&quot;([^\&quot;]+)&quot;&gt;([^&lt;]+)&lt;\/a&gt;/i'</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">preg_replace_callback</span><span class="br0">&#40;</span><span class="re0">$pattern</span><span class="sy0">,</span> <span class="st0">&quot;aioseop_filter_callback&quot;</span><span class="sy0">,</span> <span class="re0">$content</span><span class="br0">&#41;</span><span class="sy0">;</span></div></li>
<li class="li1"><div class="de1">&nbsp; &nbsp; <span class="br0">&#125;</span></div></li>
</ol>
        </div>
    </div>
</div>

<p>и переписать её:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p70729">
        <div class="code php" id="p707code29">
<span class="kw2">function</span> aioseop_list_pages<span class="br0">&#40;</span><span class="re0">$content</span><span class="br0">&#41;</span><span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$matches</span> <span class="sy0">=</span> <span class="kw1">array</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">preg_match_all</span><span class="br0">&#40;</span><span class="st_h">'/&lt;li class=&quot;page_item page-item-(\d+)/i'</span><span class="sy0">,</span> <span class="re0">$content</span><span class="sy0">,</span> <span class="re0">$matches</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; update_postmeta_cache<span class="br0">&#40;</span><span class="kw3">array_values</span><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#91;</span>1<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">unset</span><span class="br0">&#40;</span><span class="re0">$matches</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="re0">$pattern</span> <span class="sy0">=</span> <span class="st_h">'/&lt;li class=&quot;page_item page-item-(\d+)([^\&quot;]*)&quot;&gt;&lt;a href=\&quot;([^\&quot;]+)&quot; title=&quot;([^\&quot;]+)&quot;&gt;([^&lt;]+)&lt;\/a&gt;/i'</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="kw3">preg_replace_callback</span><span class="br0">&#40;</span><span class="re0">$pattern</span><span class="sy0">,</span> <span class="st0">&quot;aioseop_filter_callback&quot;</span><span class="sy0">,</span> <span class="re0">$content</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">return</span> <span class="re0">$content</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span>
        </div>
    </div>
</div>

</li>
</ol>
<p>Это поможет избавиться от лишних запросов.</p>
<p><a href="http://blog.sjinks.pro/tag/patch/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  патч">Патч</a> в формате unified diff (внимание, формат концов строк может различаться):</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p70730">
        <div class="code diff" id="p707code30">
--- all_in_one_seo_pack.orig.php&nbsp; &nbsp; 2009-12-16 09:37:23.000000000 +0200<br />
<span class="re4">+++ all_in_one_seo_pack.php <span class="nu0">2009</span>-<span class="nu0">12</span>-<span class="nu0">17</span> 06:00:<span class="nu0">32.000000000</span> +0200</span><br />
<span class="re6">@@ -<span class="nu0">632</span>,<span class="nu0">7</span> +<span class="nu0">632</span>,<span class="nu0">7</span> @@</span><br />
&nbsp;<span class="br0">&#125;</span><br />
&nbsp;<br />
&nbsp;if<span class="br0">&#40;</span>$aioseop_options<span class="br0">&#91;</span>'aiosp_enabled'<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#123;</span><br />
<span class="re7">- &nbsp; add_action<span class="br0">&#40;</span>'wp_list_pages', 'aioseop_list_pages'<span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; add_filter<span class="br0">&#40;</span>'wp_list_pages', 'aioseop_list_pages'<span class="br0">&#41;</span>;</span><br />
&nbsp; &nbsp; remove_action<span class="br0">&#40;</span> 'wp_head', 'rel_canonical' <span class="br0">&#41;</span>;<br />
&nbsp;<span class="br0">&#125;</span><br />
&nbsp;<br />
<span class="re6">@@ -<span class="nu0">688</span>,<span class="nu0">11</span> +<span class="nu0">688</span>,<span class="nu0">17</span> @@</span><br />
&nbsp;<br />
&nbsp;// The following two functions copied entirely and modified slightly from Sarah G's Page Menu Editor, http://wordpress.org/extend/plugins/page-menu-editor/<br />
&nbsp;function aioseop_list_pages<span class="br0">&#40;</span>$content<span class="br0">&#41;</span><span class="br0">&#123;</span><br />
<span class="re7">- &nbsp; &nbsp; &nbsp; $url = preg_replace<span class="br0">&#40;</span>array<span class="br0">&#40;</span>'/\//', '/\./', '/\-/'<span class="br0">&#41;</span>, array<span class="br0">&#40;</span>'\/', '\.', '\-'<span class="br0">&#41;</span>, get_option<span class="br0">&#40;</span>'siteurl'<span class="br0">&#41;</span><span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; $matches = array<span class="br0">&#40;</span><span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; if <span class="br0">&#40;</span>preg_match_all<span class="br0">&#40;</span>'/&lt;li class=&quot;page_item page-item-<span class="br0">&#40;</span>\d+<span class="br0">&#41;</span>/i', $content, $matches<span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span></span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; update_postmeta_cache<span class="br0">&#40;</span>array_values<span class="br0">&#40;</span>$matches<span class="br0">&#91;</span>1<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;</span><br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; unset<span class="br0">&#40;</span>$matches<span class="br0">&#41;</span>;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; $pattern = '/&lt;li class=&quot;page_item page-item-<span class="br0">&#40;</span>\d+<span class="br0">&#41;</span><span class="br0">&#40;</span><span class="br0">&#91;</span>^\&quot;<span class="br0">&#93;</span>*<span class="br0">&#41;</span>&quot;&gt;&lt;a href=\&quot;<span class="br0">&#40;</span><span class="br0">&#91;</span>^\&quot;<span class="br0">&#93;</span>+<span class="br0">&#41;</span>&quot; title=&quot;<span class="br0">&#40;</span><span class="br0">&#91;</span>^\&quot;<span class="br0">&#93;</span>+<span class="br0">&#41;</span>&quot;&gt;<span class="br0">&#40;</span><span class="br0">&#91;</span>^&lt;<span class="br0">&#93;</span>+<span class="br0">&#41;</span>&lt;\/a&gt;/i';<br />
&nbsp; &nbsp; &nbsp; &nbsp; return preg_replace_callback<span class="br0">&#40;</span>$pattern, &quot;aioseop_filter_callback&quot;, $content<span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp;<br />
<span class="re8">+ &nbsp; &nbsp; &nbsp; return $content;</span><br />
<span class="re8">+ &nbsp; <span class="br0">&#125;</span></span><br />
<span class="re8">+</span><br />
&nbsp;function aioseop_filter_callback<span class="br0">&#40;</span>$matches<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; global $wpdb;<br />
&nbsp; &nbsp; if <span class="br0">&#40;</span>$matches<span class="br0">&#91;</span>1<span class="br0">&#93;</span> &amp;&amp; !empty<span class="br0">&#40;</span>$matches<span class="br0">&#91;</span>1<span class="br0">&#93;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> $postID = $matches<span class="br0">&#91;</span>1<span class="br0">&#93;</span>;
        </div>
    </div>
</div>

<p><strong>UPDATE:</strong> обновил патч, теперь он подходит для All in One SEO Pack 1.6.8.2 и поместил патч на <a href="http://wordpress.org/support/topic/342313?replies=0">форум поддержки</a>.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/patches/707-all-in-one-seo-pack-optimization/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/patches/707-all-in-one-seo-pack-optimization/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>WP Super Cache vs HyperCache vs W3 Total Cache vs MaxSite Cache</title>
		<link>http://blog.sjinks.pro/wordpress/683-wp-supercache-vs-hypercache-vs-w3-total-cache-vs-maxsite-cache/</link>
		<comments>http://blog.sjinks.pro/wordpress/683-wp-supercache-vs-hypercache-vs-w3-total-cache-vs-maxsite-cache/#comments</comments>
		<pubDate>Fri, 06 Nov 2009 10:59:55 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Hyper Cache]]></category>
		<category><![CDATA[MaxSite Cache]]></category>
		<category><![CDATA[W3 Total Cache]]></category>
		<category><![CDATA[WP Super Cache]]></category>
		<category><![CDATA[нагрузка]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=683</guid>
		<description><![CDATA[Сравнение различных плагинов кэширования для WordPress Для WordPress написано много кэширующих плагинов, предназначенных для борьбы со слабой производительностью сервера (либо кривыми руками администратора, который не в состоянии настроить PHP/MySQL). Простой пользователь зачастую задаётся вопросом: какой же из плагинов выбрать? В данной статье я рассмотрю наиболее популярные плагины (WP Super Cache, Hyper Cache, W3 Total Cache [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/683-wp-supercache-vs-hypercache-vs-w3-total-cache-vs-maxsite-cache/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Сравнение различных плагинов кэширования для <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a></em></h2>
<p>Для WordPress написано много кэширующих плагинов, предназначенных для борьбы со слабой производительностью сервера (либо кривыми руками администратора, который не в состоянии настроить PHP/<a href="http://blog.sjinks.pro/tag/mysql/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MySQL">MySQL</a>). Простой пользователь зачастую задаётся вопросом: какой же из плагинов выбрать?</p>
<p>В данной статье я рассмотрю наиболее популярные плагины (<a href="http://blog.sjinks.pro/tag/wp-super-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WP Super Cache">WP Super Cache</a>, Hyper Cache, <a href="http://blog.sjinks.pro/tag/w3-total-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  W3 Total Cache">W3 Total Cache</a> и <a href="http://blog.sjinks.pro/tag/maxsite-cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  MaxSite Cache">MaxSite Cache</a>), а затем расскажу о результатах жестокого теста, которому я подверг все эти плагины.<span id="more-683"></span></p>
<p>Прежде, чем перейти к делу, отмечу, что я <strong>не фанат</strong> ни одного из плагинов и <strong>не использую</strong> их на своих сайтах, считая, что овчинка не стоит выделки: будущее за динамическими страницами <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Поехали.</p>
<ol>
<li><a href="http://wordpress.org/extend/plugins/wp-super-cache/">WP Super Cache</a> написан Donncha O&#8217;Caoimh, одним из разработчиков WordPress. Про своё отношение к этому плагину я уже <a href="http://blog.sjinks.pro/?s=Super+Cache">писал</a>. Плагин разрабатывался как замена WP-Cache. Ключевой особенностью плагина является генерация статических <a href="http://blog.sjinks.pro/tag/html/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  HTML">HTML</a>-страниц таким образом, что они будут отдаваться Web-сервером — минуя PHP.</li>
<li><a href="http://wordpress.org/extend/plugins/hyper-cache/">Hyper Cache</a>. С ним я тоже <a href="http://blog.sjinks.pro/wordpress/patches/98-hyper-cache-compressed-content/">сталкивался</a>, и какое-то время плагин стоял у меня на сайте. Плагин написан гораздо проще, чем WP Super Cache и имеет более высокий рейтинг на wordpress.org.</li>
<li><a href="http://wordpress.org/extend/plugins/w3-total-cache/">W3 Total Cache</a> — новое слово в кэшировании. Поддерживает сжатие скриптов, CSS, <a href="http://blog.sjinks.pro/tag/cache/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  кэш">кэш</a> для базы данных, работу с CDN и многое другое.</li>
<li><a href="http://maxsite.org/page/maxsite-cache">MaxSite Cache</a> — отечественная разработка, при этом платная. Я тестировал Lite-версию, так как покупать полную версию чисто для тестирования желания нет. По словам автора, выйдет абсолютным победителем при сравнении с WP Super Cache и компанией.</li>
</ol>
<p>Для теста была взята машина такое конфигурации: Intel(R) Xeon(R) CPU X3320 @ 2.50GHz, 4 ядра, 3 MiB кэш, 8 GiB DDR-2 RAM, 2×500 GB SATA, RAID1 (ARC-1210 4-Port PCI-Express to SATA RAID Controller), 82572EI Gigabit Ethernet Controller.<br />
Операционная система: Ubuntu 9.10 64-bit Server Edition<br />
Веб-сервер: nginx 0.8.19<br />
PHP: 5.2.10.dfsg.1-2ubuntu6.1 (<a href="http://blog.sjinks.pro/tag/fastcgi/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  FastCGI">FastCGI</a>) + xCache 1.2.2-5, 75 процессов.</p>
<p>На тестируемой странице 25 несложных запросов, время их выполнения — 0.00993 сек.</p>
<p>На сайт натравливался ApacheBench — 10,000 запросов в 100…500 потоков. Это создаёт весьма приличную нагрузку, так как запросы идут один за другим.</p>
<p>Базовая нагрузка — 100 параллельных потоков. Я увеличивал количество потоков до тех пор, пока web-сервер не стал отдавать ответ, отличный от 200. Более 500 потоков не тестировал.</p>
<table cellpadding="0" cellspacing="0" class="bordered" rules="all">
<thead>
<tr>
<th>&nbsp;</th>
<th>WordPress</th>
<th colspan="2">WP Super Cache 0.9.7</th>
<th colspan="2">Hyper Cache 2.6.2</th>
<th colspan="3">MaxSite Cache Lite</th>
<th colspan="2">W3 Total Cache 0.8</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Количество потоков</th>
<td>100</td>
<td>100</td>
<td>500</td>
<td>100</td>
<td>250</td>
<td>100</td>
<td>500</td>
<td>130</td>
<td>100</td>
<td>130</td>
</tr>
<tr>
<th scope="row">Время тестирования, с</th>
<td>677.442</td>
<td class="good">1.115</td>
<td class="good">1.079</td>
<td>18.736</td>
<td class="unreliable">8.633</td>
<td>3.291</td>
<td class="unreliable">2.501</td>
<td>2.992</td>
<td>21.284</td>
<td>21.086</td>
</tr>
<tr>
<th scope="row">Количество ошибок</th>
<td>0</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td class="imp">3663</td>
<td>0</td>
<td class="imp">2713</td>
<td>0</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<th scope="row">Скорость, запрос/с</th>
<td>14.76</td>
<td class="good">8967.28</td>
<td class="good">9268.36</td>
<td>544.20</td>
<td class="unreliable">1158.30</td>
<td class="good">3038.98</td>
<td class="unreliable">3997.80</td>
<td class="good">3341.72</td>
<td>469.84</td>
<td>474.25</td>
</tr>
<tr>
<th scope="row">Среднее время обработки запроса, мс</th>
<td>6774.423</td>
<td>11.152</td>
<td>53.947</td>
<td>183.757</td>
<td class="unreliable">215.833</td>
<td>32.906</td>
<td class="unreliable">125.069</td>
<td>38.902</td>
<td>212.838</td>
<td>274.116</td>
</tr>
<tr>
<th scope="row">Среднее время обработки запроса по всем потокам, мс</th>
<td>67.744</td>
<td class="good">0.112</td>
<td class="good">0.108</td>
<td>1.838</td>
<td class="unreliable">0.863</td>
<td class="good">0.329</td>
<td class="unreliable">0.250</td>
<td class="good">0.299</td>
<td>2.128</td>
<td>2.109</td>
</tr>
<tr>
<th scope="row">Скорость передачи, Кбайт/с</th>
<td>175.12</td>
<td class="good">106154.90</td>
<td class="good">109865.55</td>
<td>6393.68</td>
<td class="unreliable">8754.04</td>
<td class="good">35537.15</td>
<td class="unreliable">34413.87</td>
<td class="good">39075.95</td>
<td>4928.74</td>
<td>4974.58</td>
</tr>
<tr>
<th scope="row">Порог завершения 95% запросов, мс</th>
<td>9188</td>
<td class="good">11</td>
<td class="good">27</td>
<td>394</td>
<td class="unreliable">268</td>
<td class="good">52</td>
<td class="unreliable">91</td>
<td class="good">58</td>
<td>344</td>
<td>364</td>
</tr>
</tbody>
</table>
<p>То, что не вошло в таблицу: средняя загрузка системы (load average) при тесте голого WordPress зашкаливала за 60. При тесте WP Super Cache и MaxSite Cache я не успевал ее измерить (была ничтожной). С Hyper Cache и W3 Total Cache загрузка доходила до где-то 10. Так что <strong>кэширование работает и выполняет свою работу — снижает нагрузку на сервер</strong>.</p>
<p>«Голый» WordPress тестировать более, чем со 100 потоками смысла нет <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>В ходе тестирования выяснился абсолютный лидер — WP Super Cache. Скорость отдачи кэшированных страниц поистине фантастическая — почти 800 мегабит/сек. Хотя такая скорость — это больше заслуга nginx.</p>
<p>MaxSite Cache Lite на 100 параллельных потоках проиграл WP Super Cache <strong>практически в пять раз</strong>! Причина понятна: WP Super Cache создает статические файлы так, что web-сервер их может отдавать клиенту без привлечения PHP-интерпретатора. А статические запросы при прочих равных всегда быстрее динамических. Так что платить 30 WMZ за полную версию MaxSite Cache я пока не готов <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Среди остальных плагинов MaxSite Cache выигрывает благодаря свой простоте: минимум проверок, никаких регулярных выражений и лишних подключаемых файлов. Но даже такой подход не спасёт от хорошего SlashDot-эффекта: какой-то процент пользователей будет видеть ошибку сервера, для других возрастёт время генерации страницы. Это касается и остальных плагинов. Мораль: подключение PHP-интерпретатора — дорогое удовольствие.</p>
<p>По поводу масштабируемости: более 130 потоков не пережил ни один кэш (кроме WP Super Cache).</p>
<p>Аутсайдером, на мой взгляд, оказался W3 Total Cache — при почти одинаковой с Hyper Cache нагрузкой на сервер, время отдачи страниц было значительно выше. Хотя если бы тест был не таким искусственным, то <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a> W3 Total Cache могла быть и более высокой. Хотя во многом W3 Total Cache делает то, что <a href="http://blog.sjinks.pro/feedback/">опытный системный администратор</a> может настроить на уровне сервера.</p>
<p>Вообще плагины кэширования обладают очень интересной особенностью: они переносят нагрузку с одной подсистемы (процессор) на другую (диск). Так что на десктопном железе, слабых дисках или виртуальных серверах <strong>кэш может ухудшить ситуацию</strong>: процессор будет тратить время не на выполнение кода, а на ожидание завершения ввода/вывода (iowait). Так что при большом количестве оперативной памяти имеет смысл создавать RAM-диск и помещать кэш на него.</p>
<p>Кстати, даже при хорошей дисковой подсистеме, но при малом объеме оперативной памяти при большом объеме кэша могут возникать проблемы: например, если дисковый кэш у операционной системы мал, то при интенсивном равномерном обращении к разным страницам может возникнуть большая дисковая активность.</p>
<p>Вообще, как показывает мой опыт, прежде чем использовать плагин кэширования страниц, имеет смысл все же грамотно настроить сервер (<a href="http://blog.sjinks.pro/feedback/">обращайтесь</a>). Например, если вместо Apache поставить nginx, можно освободить довольно много драгоценной памяти (prefork у Apache — это весьма сильный убийца производительности); если увеличить размер буфера ключей MySQL, можно добиться уменьшения дисковой активности. Если поставить opcode cacher (APC, xCache, <a href="http://blog.sjinks.pro/tag/eaccelerator/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  eAccelerator">eAccelerator</a>), то можно значительно снизить затраты на перекомпиляцию PHP-кода и уменьшить время отклика системы. Если использовать оптимизатор, встроенный в <a href="http://blog.sjinks.pro/tag/eaccelerator/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  eAccelerator">eAccelerator</a>, то можно <a href="http://blog.sjinks.pro/php/650-php-code-beauty-impacts-performance/">повысить производительность PHP-кода</a>. <a href="http://wordpress.org/extend/plugins/sqlmon/">Анализ производительности MySQL-запросов</a> и знание принципов работы оптимизатора помогут переписать слабые запросы/добавить отсутствующие индексы в базу данных. Простор для действий довольно-таки большой. И динамика страниц остаётся <img src='http://static.sjinks.info/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/683-wp-supercache-vs-hypercache-vs-w3-total-cache-vs-maxsite-cache/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/683-wp-supercache-vs-hypercache-vs-w3-total-cache-vs-maxsite-cache/feed/</wfw:commentRss>
		<slash:comments>53</slash:comments>
		</item>
		<item>
		<title>PHP: красота кода сказывается на производительности: часть 2</title>
		<link>http://blog.sjinks.pro/php/651-php-code-beauty-impacts-performance-part-2/</link>
		<comments>http://blog.sjinks.pro/php/651-php-code-beauty-impacts-performance-part-2/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 01:23:25 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[оптимизация]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=651</guid>
		<description><![CDATA[Как же всё запущено В прошлой части: if быстрее, чем switch; echo быстрее, чем print; явная проверка на (не)нулевое значение медленнее, чем неявная. А также: константные выражения, которые могут быть вычислены на этапе компиляции, не вычисляются; PHP не умеет удалять неиспользуемый код на этапе компиляции. Продолжим. Конкатенация или переменные внутри строки? &#160; Конкатенация Переменные внутри [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/651-php-code-beauty-impacts-performance-part-2/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Как же всё запущено</em></h2>
<p>В <a href="http://blog.sjinks.pro/php/650-php-code-beauty-impacts-performance/">прошлой части</a>:</p>
<ul>
<li><span class="codebox"><code class="php"><span class="kw1">if</span></code></span> быстрее, чем <span class="codebox"><code class="php"><span class="kw1">switch</span></code></span>;</li>
<li><span class="codebox"><code class="php"><span class="kw1">echo</span></code></span> быстрее, чем <span class="codebox"><code class="php"><span class="kw1">print</span></code></span>;</li>
<li>явная проверка на (не)нулевое значение медленнее, чем неявная.</li>
</ul>
<p><a href="http://blog.sjinks.pro/php/638-byte-code-optimization-in-php/">А также</a>: </p>
<ul>
<li>константные выражения, которые могут быть вычислены на этапе компиляции, не вычисляются;</li>
<li><a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a> не умеет удалять неиспользуемый код на этапе компиляции.</li>
</ul>
<p>Продолжим.<span id="more-651"></span></p>
<h3>Конкатенация или переменные внутри строки?</h3>
<table class="bordered" style="width: 99%; table-layout:fixed">
<thead>
<tr>
<th style="width: 100px">&nbsp;</th>
<th style="width: 50%">Конкатенация</th>
<th style="width: 50%">Переменные внутри строки</th>
</tr>
</thead>
<tbody style="vertical-align: top">
<tr>
<th scope="row">Код</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65153">
        <div class="code php" id="p651code53">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$tpl</span> &nbsp;<span class="sy0">=</span> <span class="st0">&quot;str2&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$text</span> <span class="sy0">=</span> <span class="st_h">'str1 '</span> <span class="sy0">.</span> <span class="re0">$tpl</span> <span class="sy0">.</span> <span class="st0">&quot; str3<span class="es1">\n</span>&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="re0">$text</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65154">
        <div class="code php" id="p651code54">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$tpl</span> &nbsp;<span class="sy0">=</span> <span class="st0">&quot;str2&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$text</span> <span class="sy0">=</span> <span class="st0">&quot;str1 <span class="es4">{$tpl}</span> str3<span class="es1">\n</span>&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="re0">$text</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
</tr>
<tr>
<th>Результат</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65155">
        <div class="code text" id="p651code55">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $tpl, 'str2'<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 1 &nbsp;CONCAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;'str1 ', $tpl<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;CONCAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~2 &nbsp; &nbsp; &nbsp;~1, ' str3\n'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $text, ~2<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 4 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $text<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 5 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65156">
        <div class="code text" id="p651code56">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $tpl, 'str2'<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 1 &nbsp;INIT_STRING &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;~1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;ADD_STRING &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;~1, 'str1 '<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;ADD_VAR &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;~1 &nbsp; &nbsp; &nbsp;~1, $tpl<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;ADD_STRING &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;~1, ' str3\n'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;5 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $text, ~1<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 6 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $text<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 7 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;8* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
</tr>
</tbody>
</table>
<p><strong>Вывод:</strong> конкатенация быстрее, и, как показал тест (путём замены <span class="codebox"><code class="php"><span class="kw1">echo</span> <span class="re0">$text</span><span class="sy0">;</span></code></span> на <span class="codebox"><code class="php"><span class="kw1">echo</span> <span class="kw3">memory_get_usage</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span></code></span>), потребляет меньше памяти.</p>
<h3>Цикл со счётчиком: <span class="codebox"><code class="php"><span class="kw1">while</span></code></span> или <span class="codebox"><code class="php"><span class="kw1">for</span></code></span>?</h3>
<table class="bordered" style="width: 99%; table-layout:fixed">
<thead>
<tr>
<th style="width: 100px">&nbsp;</th>
<th style="width: 50%"><span class="codebox"><code class="php"><span class="kw1">for</span></code></span></th>
<th style="width: 50%"><span class="codebox"><code class="php"><span class="kw1">while</span></code></span></th>
</tr>
</thead>
<tbody style="vertical-align: top">
<tr>
<th scope="row">Код</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65157">
        <div class="code php" id="p651code57">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw1">for</span> <span class="br0">&#40;</span><span class="re0">$i</span><span class="sy0">=</span><span class="nu0">0</span><span class="sy0">;</span> <span class="re0">$i</span><span class="sy0">&lt;</span><span class="nu0">1000</span><span class="sy0">;</span> <span class="sy0">++</span><span class="re0">$i</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65158">
        <div class="code php" id="p651code58">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$i</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">while</span> <span class="br0">&#40;</span><span class="re0">$i</span><span class="sy0">&lt;</span>1000<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="sy0">++</span><span class="re0">$i</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
</tr>
<tr>
<th>Результат</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65159">
        <div class="code text" id="p651code59">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $i, 0<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp;IS_SMALLER &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;$i, 1000<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;JMPZNZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;5 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;~1, -&gt;6<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;PRE_INC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$i<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;1<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 5 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;3<br />
&nbsp; &nbsp;7 &nbsp; &nbsp; 6 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65160">
        <div class="code text" id="p651code60">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $i, 0<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 1 &nbsp;IS_SMALLER &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;$i, 1000<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1, -&gt;5<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 3 &nbsp;PRE_INC &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;!0<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 4 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;1<br />
&nbsp; &nbsp;9 &nbsp; &nbsp; 5 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
</tr>
</tbody>
</table>
<p><strong>Вывод:</strong> хотя цикл <span class="codebox"><code class="php"><span class="kw1">while</span></code></span> выглядит многословнее (по крайней мере, длиннее), он, на удивление, оказывается короче полностью аналогичного цикла <span class="codebox"><code class="php"><span class="kw1">for</span></code></span>. Таким образом, не всегда более короткий код оказывается более эффективным. При этом так как второй вариант короче (в плане количества опкодов), он потребляет меньше памяти.</p>
<h3>Пустая строка или <span class="codebox"><code class="php"><span class="kw4">NULL</span></code></span>?</h3>
<table class="bordered" style="width: 99%; table-layout:fixed">
<thead>
<tr>
<th style="width: 100px">&nbsp;</th>
<th style="width: 50%">Пустая строка</th>
<th style="width: 50%"><span class="codebox"><code class="php"><span class="kw4">null</span></code></span></th>
</tr>
</thead>
<tbody style="vertical-align: top">
<tr>
<th scope="row">Код</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65161">
        <div class="code php" id="p651code61">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="st0">&quot;&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="kw3">memory_get_usage</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65162">
        <div class="code php" id="p651code62">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="kw4">NULL</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="kw3">memory_get_usage</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
</tr>
<tr>
<th>Результат</th>
<td>106,336</td>
<td>106,224</td>
</tr>
</tbody>
</table>
<p><strong>Вывод:</strong> использование пустых значений «сложных» типов (строки, массивы, объекты) ведёт к повышенному потреблению памяти. Использование <code>NULL</code> — самый оптимальный вариант.</p>
<h3><span class="codebox"><code class="php"><span class="kw3">is_null</span><span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> или строгая проверка на <span class="codebox"><code class="php"><span class="kw4">NULL</span></code></span>?</h3>
<table class="bordered" style="width: 99%; table-layout:fixed">
<thead>
<tr>
<th style="width: 100px">&nbsp;</th>
<th style="width: 50%"><span class="codebox"><code class="php"><span class="kw3">is_null</span></code></span></th>
<th style="width: 50%">Строгое соответствие</th>
</tr>
</thead>
<tbody style="vertical-align: top">
<tr>
<th scope="row">Код</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65163">
        <div class="code php" id="p651code63">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw3">is_null</span><span class="br0">&#40;</span><span class="re0">$a</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65164">
        <div class="code php" id="p651code64">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="nu0">0</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$a</span> <span class="sy0">===</span> <span class="kw4">NULL</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
</tr>
<tr>
<th>Результат</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65165">
        <div class="code text" id="p651code65">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, 0<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 1 &nbsp;SEND_VAR &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;DO_FCALL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'is_null'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $1, -&gt;5<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 4 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;5<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 5 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65166">
        <div class="code text" id="p651code66">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, 0<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 1 &nbsp;IS_IDENTICAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;$a, null<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1, -&gt;4<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 3 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;4<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 4 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;5* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
</tr>
</tbody>
</table>
<p><strong>Вывод:</strong> проверка на строгое равенство NULL работает быстрее, в том числе из-за отсутствия необходимости вызова функции.</p>
<h3><span class="codebox"><code class="php"><span class="kw1">echo</span></code></span>: конкатенация или запятые?</h3>
<table class="bordered" style="width: 99%; table-layout:fixed">
<thead>
<tr>
<th style="width: 100px">&nbsp;</th>
<th style="width: 50%">Конкатенация</th>
<th style="width: 50%">Запятые</th>
</tr>
</thead>
<tbody style="vertical-align: top">
<tr>
<th scope="row">Код</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65167">
        <div class="code php" id="p651code67">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="st_h">'Memory '</span> <span class="sy0">.</span> <span class="st_h">'usage '</span> <span class="sy0">.</span> <span class="st_h">'is '</span> <span class="sy0">.</span> <span class="kw3">memory_get_usage</span><span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="sy0">.</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65168">
        <div class="code php" id="p651code68">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw1">echo</span> <span class="st_h">'Memory '</span><span class="sy0">,</span> <span class="st_h">'usage '</span><span class="sy0">,</span> <span class="st_h">'is '</span><span class="sy0">,</span> <span class="kw3">memory_get_usage</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">,</span> <span class="st0">&quot;<span class="es1">\n</span>&quot;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
</tr>
<tr>
<th>Результат</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65169">
        <div class="code text" id="p651code69">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;CONCAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;'Memory ', 'usage '<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp;CONCAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;~0, 'is ' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;DO_FCALL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'memory_get_usage' <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;CONCAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3 &nbsp; &nbsp; &nbsp;~1, $2 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;CONCAT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~4 &nbsp; &nbsp; &nbsp;~3, '\n' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;5 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~4<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 6 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65170">
        <div class="code text" id="p651code70">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'Memory '<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'usage '<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 'is '<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;DO_FCALL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'memory_get_usage'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $0<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;5 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '\n'<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 6 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
</tr>
<tr>
<th scope="row">&nbsp;</th>
<td>
Memory usage is 106192
</td>
<td>
Memory usage is 106184
</td>
</tr>
</tbody>
</table>
<p><strong>Выводы:</strong> в очередной раз менее читабельный метод оказался лучшим — на этот раз в плане потребления памяти. И, как видим, PHP не догадался даже объединить строки вместе.</p>
<h3>Что быстрее: статический или динамический метод?</h3>
<table class="bordered" style="width: 99%; table-layout:fixed">
<thead>
<tr>
<th style="width: 100px">&nbsp;</th>
<th style="width: 50%">Динамический метод</th>
<th style="width: 50%">Статический метод</th>
</tr>
</thead>
<tbody style="vertical-align: top">
<tr>
<th scope="row">Код</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65171">
        <div class="code php" id="p651code71">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw2">class</span> A <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">function</span> test<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="kw2">new</span> A<span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="re0">$a</span><span class="sy0">-&gt;</span><span class="me1">test</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65172">
        <div class="code php" id="p651code72">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="kw2">class</span> A <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">public</span> <span class="kw2">static</span> <span class="kw2">function</span> test<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="kw2">new</span> A<span class="sy0">;</span><br />
&nbsp; &nbsp; A<span class="sy0">::</span><span class="me2">test</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy0">;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

</td>
</tr>
<tr>
<th>Результат</th>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65173">
        <div class="code text" id="p651code73">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;NOP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 1 &nbsp;ZEND_FETCH_CLASS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :1 &nbsp; &nbsp; &nbsp;'A' &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;NEW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$2 &nbsp; &nbsp; &nbsp;:1 &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;DO_FCALL_BY_NAME &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, $2 &nbsp; &nbsp;<br />
&nbsp; &nbsp;7 &nbsp; &nbsp; 5 &nbsp;ZEND_INIT_METHOD_CALL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$5 &nbsp; &nbsp; &nbsp;$a, 'test'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp;DO_FCALL_BY_NAME &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp;8 &nbsp; &nbsp; 7 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;8* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
<td>
          
<div class="codebox">
    <div class="the_code" style="" id="p65174">
        <div class="code text" id="p651code74">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;NOP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 1 &nbsp;ZEND_FETCH_CLASS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :1 &nbsp; &nbsp; &nbsp;'A' &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;NEW &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$2 &nbsp; &nbsp; &nbsp;:1 &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;DO_FCALL_BY_NAME &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, $2 &nbsp; &nbsp;<br />
&nbsp; &nbsp;7 &nbsp; &nbsp; 5 &nbsp;ZEND_FETCH_CLASS &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :5 &nbsp; &nbsp; &nbsp;'A' &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp;ZEND_INIT_STATIC_METHOD_CALL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; null, 'test'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7 &nbsp;DO_FCALL_BY_NAME &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<br />
&nbsp; &nbsp;8 &nbsp; &nbsp; 8 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;9* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

</td>
</tr>
</tbody>
</table>
<p><strong>Выводы:</strong> при прочих равных условиях, вызов статического метода на один опкод длиннее вызова динамического метода. Таким образом, если делать все методы класса, которые не используют <span class="codebox"><code class="php"><span class="re0">$this</span></code></span>, статическими, это приведёт к потреблению памяти.</p>
<p>Спички спичками, но сколько таких спичек экономится в мало-мальски сложном скрипте (таком, как <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a>). Пусть результат от одной сэкономленной спички ничтожно мал, но помноженный на количество таких потенциальных спичек во всём коде, становится весьма и весьма ощутимым, особенно на слабом железе.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/651-php-code-beauty-impacts-performance-part-2/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/651-php-code-beauty-impacts-performance-part-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>PHP: красота кода сказывается на производительности</title>
		<link>http://blog.sjinks.pro/php/650-php-code-beauty-impacts-performance/</link>
		<comments>http://blog.sjinks.pro/php/650-php-code-beauty-impacts-performance/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 01:14:52 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[eAccelerator]]></category>
		<category><![CDATA[оптимизация]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=650</guid>
		<description><![CDATA[Читабельный код выполняется медленнее Недавно я для себя открыл, что PHP не умеет оптимизировать код, а тут новый удар: оказывается, что красота кода отрицательно влияет на производительность. Как и в прошлый раз, для проверки гипотез использовался Vulcan Logic Disassembler. Сравнивались два куска кода: Тест №1: &#60;?php $a = true; if (true == $a) { print [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/650-php-code-beauty-impacts-performance/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Читабельный код выполняется медленнее</em></h2>
<p>Недавно я для себя открыл, что <a href="http://blog.sjinks.pro/php/638-byte-code-optimization-in-php/"><strong>PHP не умеет оптимизировать код</strong></a>, а тут новый удар: оказывается, что красота кода отрицательно влияет на <a href="http://blog.sjinks.pro/tag/performance/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  производительность">производительность</a>.<span id="more-650"></span></p>
<p>Как и в прошлый раз, для проверки гипотез использовался <a href="http://pecl.php.net/package/vld/">Vulcan Logic Disassembler</a>.</p>
<p>Сравнивались два куска кода:</p>
<p><strong>Тест №1:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65087">
        <div class="code php" id="p650code87">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="kw4">true</span> <span class="sy0">==</span> <span class="re0">$a</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>и абсолютно аналогичный по функциональности</p>
<p><strong>Тест №2:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65088">
        <div class="code php" id="p650code88">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="kw4">true</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$a</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">print</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p>На выходе получилась такая картина.<br />
<strong>Для первого случая:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65089">
        <div class="code text" id="p650code89">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;FETCH_CONSTANT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;'true'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, ~0<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 2 &nbsp;FETCH_CONSTANT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~2 &nbsp; &nbsp; &nbsp;'true'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;IS_EQUAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3 &nbsp; &nbsp; &nbsp;~2, $a<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3, -&gt;8<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 5 &nbsp;PRINT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;~4 &nbsp; &nbsp; &nbsp;1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp;FREE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~4<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 7 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;8<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 8 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;9* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p><strong>Для второго случая:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65090">
        <div class="code text" id="p650code90">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;FETCH_CONSTANT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;'true'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, ~0<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 2 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, -&gt;6<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 3 &nbsp;PRINT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;~2 &nbsp; &nbsp; &nbsp;1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;FREE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~2<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 5 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;6<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 6 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p>Видим, что в первом случае <a href="http://blog.sjinks.pro/tag/php/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  PHP">PHP</a>, как мы его и попросили, честно сравнил <span class="codebox"><code class="php"><span class="kw4">true</span></code></span> c <span class="codebox"><code class="php"><span class="re0">$a</span></code></span> и проверил, равен ли результат сравнения нулю или нет. Во втором же случае PHP просто проверил, равно ли <span class="codebox"><code class="php"><span class="re0">$a</span></code></span> нулю, сэкономив два опкода.</p>
<p>Будучи любопытным, я заменил проверку на равенство <span class="codebox"><code class="php"><span class="kw4">true</span></code></span> проверкой на неравенство <span class="codebox"><code class="php"><span class="kw4">false</span></code></span>. Хрен редьки не слаще: те же 9 опкодов:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65091">
        <div class="code text" id="p650code91">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;FETCH_CONSTANT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;'true'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, ~0<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 2 &nbsp;FETCH_CONSTANT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~2 &nbsp; &nbsp; &nbsp;'false'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;IS_NOT_EQUAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3 &nbsp; &nbsp; &nbsp;~2, $a<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3, -&gt;8<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 5 &nbsp;PRINT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;~4 &nbsp; &nbsp; &nbsp;1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp;FREE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~4<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 7 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;8<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 8 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;9* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p>Попутно выяснил, что те, кто говорят, что <span class="codebox"><code class="php"><span class="kw1">echo</span></code></span> быстрее, чем <span class="codebox"><code class="php"><span class="kw1">print</span></code></span>, правы. Я поменял <span class="codebox"><code class="php"><span class="kw1">print</span> <span class="nu0">1</span></code></span>; на <span class="codebox"><code class="php"><span class="kw1">echo</span> <span class="nu0">1</span></code></span>, в результате код программы сократился на один опкод:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65092">
        <div class="code text" id="p650code92">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;FETCH_CONSTANT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;'true'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, ~0<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 2 &nbsp;FETCH_CONSTANT &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~2 &nbsp; &nbsp; &nbsp;'false'<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;3 &nbsp;IS_NOT_EQUAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3 &nbsp; &nbsp; &nbsp;~2, $a<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3, -&gt;7<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 5 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 6 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;7<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 7 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;8* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p>Затем я решил проверить, что лучше: <span class="codebox"><code class="php"><span class="kw1">switch</span></code></span> или спагетти из <span class="codebox"><code class="php"><span class="kw1">if</span></code></span>/<span class="codebox"><code class="php"><span class="kw1">elseif</span></code></span>.</p>
<p><strong>Тест №3</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65093">
        <div class="code php" id="p650code93">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="nu0">5</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span><span class="re0">$a</span> <span class="sy0">==</span> 1<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="re0">$a</span> <span class="sy0">==</span> 2<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="nu0">2</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">elseif</span> <span class="br0">&#40;</span><span class="re0">$a</span> <span class="sy0">==</span> 3<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="nu0">3</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
&nbsp; &nbsp; <span class="kw1">else</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="st0">&quot;:-(&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p><strong>Результат:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65094">
        <div class="code text" id="p650code94">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, 5<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 1 &nbsp;IS_EQUAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;$a, 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1, -&gt;5<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 3 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 4 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;14<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 5 &nbsp;IS_EQUAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~2 &nbsp; &nbsp; &nbsp;$a, 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~2, -&gt;9<br />
&nbsp; &nbsp;7 &nbsp; &nbsp; 7 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2<br />
&nbsp; &nbsp;8 &nbsp; &nbsp; 8 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;14<br />
&nbsp; &nbsp;9 &nbsp; &nbsp; 9 &nbsp;IS_EQUAL &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3 &nbsp; &nbsp; &nbsp;$a, 3<br />
&nbsp; &nbsp; &nbsp; &nbsp; 10 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~3, -&gt;13<br />
&nbsp; 10 &nbsp; &nbsp;11 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3<br />
&nbsp; 11 &nbsp; &nbsp;12 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;14<br />
&nbsp; 13 &nbsp; &nbsp;13 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ':-('<br />
&nbsp; 15 &nbsp; &nbsp;14 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; 15* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p><strong>Тест №4</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65095">
        <div class="code php" id="p650code95">
<span class="kw2">&lt;?php</span><br />
&nbsp; &nbsp; <span class="re0">$a</span> <span class="sy0">=</span> <span class="nu0">5</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="kw1">switch</span> <span class="br0">&#40;</span><span class="re0">$a</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> 1<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="nu0">1</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> 2<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="nu0">2</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">case</span> 3<span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="nu0">3</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">default</span><span class="sy0">:</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">echo</span> <span class="st0">&quot;:-(&quot;</span><span class="sy0">;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">break</span><span class="sy0">;</span><br />
&nbsp; &nbsp; <span class="br0">&#125;</span><br />
<span class="sy1">?&gt;</span>
        </div>
    </div>
</div>

<p><strong>Результат:</strong></p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65096">
        <div class="code text" id="p650code96">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, 5<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 1 &nbsp;CASE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;$a, 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1, -&gt;6<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 3 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 4 &nbsp;BRK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1<br />
&nbsp; &nbsp;7 &nbsp; &nbsp; 5* JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;8<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp;CASE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;$a, 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;7 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1, -&gt;11<br />
&nbsp; &nbsp;8 &nbsp; &nbsp; 8 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2<br />
&nbsp; &nbsp;9 &nbsp; &nbsp; 9 &nbsp;BRK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1<br />
&nbsp; 10 &nbsp; &nbsp;10* JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;13<br />
&nbsp; &nbsp; &nbsp; &nbsp; 11 &nbsp;CASE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1 &nbsp; &nbsp; &nbsp;$a, 3<br />
&nbsp; &nbsp; &nbsp; &nbsp; 12 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~1, -&gt;16<br />
&nbsp; 11 &nbsp; &nbsp;13 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3<br />
&nbsp; 12 &nbsp; &nbsp;14 &nbsp;BRK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1<br />
&nbsp; 13 &nbsp; &nbsp;15* JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;17<br />
&nbsp; &nbsp; &nbsp; &nbsp; 16 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;20<br />
&nbsp; 14 &nbsp; &nbsp;17 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ':-('<br />
&nbsp; 15 &nbsp; &nbsp;18 &nbsp;BRK &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1<br />
&nbsp; 16 &nbsp; &nbsp;19* JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;21<br />
&nbsp; &nbsp; &nbsp; &nbsp; 20 &nbsp;JMP &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;-&gt;17<br />
&nbsp; 17 &nbsp; &nbsp;21 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; 22* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p>Результат для <span class="codebox"><code class="php"><span class="kw1">switch</span></code></span> хоть и более читаемый, но оказался в полтора раза хуже результата для <span class="codebox"><code class="php"><span class="kw1">if</span></code></span>. Sad but true.</p>
<p>После этого я собрал (с поддержкой оптимизатора) и поставил <a href="http://blog.sjinks.pro/tag/eaccelerator/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  eAccelerator">eAccelerator</a> и повторил тесты.</p>
<p><strong>Тест №1</strong> и <strong>тест №2</strong> дали одинаковый результат:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65097">
        <div class="code text" id="p650code97">
line &nbsp; &nbsp; # &nbsp;op &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; fetch &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ext &nbsp;return &nbsp;operands<br />
-------------------------------------------------------------------------------<br />
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, true<br />
&nbsp; &nbsp;3 &nbsp; &nbsp; 1 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, -&gt;3<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 2 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp;6 &nbsp; &nbsp; 3 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;4* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p>Что характерно, eAccelerator самостоятельно преобразовал <span class="codebox"><code class="php"><span class="kw1">print</span></code></span> в <span class="codebox"><code class="php"><span class="kw1">echo</span></code></span>. Лапочка.</p>
<p>Для <strong>теста №3</strong> результат остался неизменным: там, собственно, нечего оптимизировать.</p>
<p>А результаты <strong>теста №4</strong> впечатлили:</p>
          
<div class="codebox">
    <div class="the_code" style="" id="p65098">
        <div class="code text" id="p650code98">
&nbsp; &nbsp;2 &nbsp; &nbsp; 0 &nbsp;ASSIGN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $a, 5<br />
&nbsp; &nbsp;4 &nbsp; &nbsp; 1 &nbsp;CASE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;$a, 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;2 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0, -&gt;5<br />
&nbsp; &nbsp;5 &nbsp; &nbsp; 3 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; 17 &nbsp; &nbsp; 4 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp;7 &nbsp; &nbsp; 5 &nbsp;CASE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;$a, 2<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;6 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0, -&gt;9<br />
&nbsp; &nbsp;8 &nbsp; &nbsp; 7 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 2<br />
&nbsp; 17 &nbsp; &nbsp; 8 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; 10 &nbsp; &nbsp; 9 &nbsp;CASE &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0 &nbsp; &nbsp; &nbsp;$a, 3<br />
&nbsp; &nbsp; &nbsp; &nbsp; 10 &nbsp;JMPZ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ~0, -&gt;13<br />
&nbsp; 11 &nbsp; &nbsp;11 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 3<br />
&nbsp; 17 &nbsp; &nbsp;12 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; 14 &nbsp; &nbsp;13 &nbsp;ECHO &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ':-('<br />
&nbsp; 17 &nbsp; &nbsp;14 &nbsp;RETURN &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1<br />
&nbsp; &nbsp; &nbsp; &nbsp; 15* ZEND_HANDLE_EXCEPTION
        </div>
    </div>
</div>

<p>На выходе получили результат, который по эффективности аналогичен коду из <span class="codebox"><code class="php"><span class="kw1">if</span></code></span>!</p>
<p>Поэтому в заключение скажу: ставьте eAccelerator и будет всем счастье!</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/php/650-php-code-beauty-impacts-performance/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/php/650-php-code-beauty-impacts-performance/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>SJ Hook Profiler — плагин для измерения производительности хуков</title>
		<link>http://blog.sjinks.pro/wordpress/plugins/642-sj-hook-profiler/</link>
		<comments>http://blog.sjinks.pro/wordpress/plugins/642-sj-hook-profiler/#comments</comments>
		<pubDate>Mon, 21 Sep 2009 23:01:11 +0000</pubDate>
		<dc:creator>Vladimir</dc:creator>
				<category><![CDATA[bbPress]]></category>
		<category><![CDATA[Плагины WordPress]]></category>
		<category><![CDATA[SJ Hook Profiler]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[оптимизация]]></category>
		<category><![CDATA[плагин]]></category>
		<category><![CDATA[производительность]]></category>

		<guid isPermaLink="false">http://blog.sjinks.pro/?p=642</guid>
		<description><![CDATA[Поиск слабых мест в WordPress и bbPress Сразу оговорюсь, что речь пойдёт совсем не о боксе, а о WordPress и bbPress. Разработчики плагинов WordPress и bbPress используют две функции для расширения функциональности WordPress/bbPress: это add_action() и add_filter(). Первая служит для установки обработчика некоторого события, вторая — для установки фильтра. Под хуком подразумевается обобщённое понятие (либо фильтр, [...]<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/plugins/642-sj-hook-profiler/">источник</a> обязательно.</p>]]></description>
			<content:encoded><![CDATA[<h2><em>Поиск слабых мест в <a href="http://blog.sjinks.pro/tag/wordpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  WordPress">WordPress</a> и <a href="http://blog.sjinks.pro/tag/bbpress/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  bbPress">bbPress</a></em></h2>
<p>Сразу оговорюсь, что речь пойдёт совсем не о боксе, а о WordPress и bbPress.</p>
<p>Разработчики плагинов WordPress и bbPress используют две функции для расширения функциональности WordPress/bbPress: это <span class="codebox"><code class="php">add_action<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span> и <span class="codebox"><code class="php">add_filter<span class="br0">&#40;</span><span class="br0">&#41;</span></code></span>. Первая служит для установки обработчика некоторого события, вторая — для установки фильтра. Под <dfn>хуком</dfn> подразумевается обобщённое понятие (либо фильтр, либо обработчик).</p>
<p>Как показывает практика, б<em>о</em>льшая часть времени генерации страницы уходит именно на вызов обработчиков и фильтров. И когда возникает вопрос: почему время генерации страницы такое большое, а запроса всего три, и они выполняются за сотые доли секунды, на помощь приходит данный <a href="http://blog.sjinks.pro/tag/plugin/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  плагин">плагин</a>.<span id="more-642"></span></p>
<p>В отличие от WP Tuner, которому явно нужно указывать, какие события нужно профилировать, <a href="http://blog.sjinks.pro/tag/sj-hook-profiler/" class="st_tag internal_tag" rel="tag" title="Записи, помеченные с  SJ Hook Profiler">SJ Hook Profiler</a> автоматически определяет <em>все</em> используемые хуки и устанавливает обработчики, измеряющие их время работы. На выходе получается что-то вида данной таблицы:</p>
<table class="hookdebug">
<thead>
<tr>
<th>Hook Name</th>
<th>Total Time</th>
<th>Invocations</th>
<th>Average Time</th>
</tr>
</thead>
<tbody>
<tr>
<td>pre_option_gmt_offset</td>
<td>0.000169</td>
<td>1</td>
<td>0.000169</td>
</tr>
<tr>
<td>option_blog_charset</td>
<td>0.000405</td>
<td>11</td>
<td>0.000037</td>
</tr>
<tr>
<td>plugins_loaded</td>
<td>0.014295</td>
<td>1</td>
<td>0.014295</td>
</tr>
<tr>
<td>option_siteurl</td>
<td>0.000810</td>
<td>26</td>
<td>0.000031</td>
</tr>
<tr>
<td>option_home</td>
<td>0.004852</td>
<td>160</td>
<td>0.000030</td>
</tr>
<tr>
<td>sanitize_comment_cookies</td>
<td>0.000117</td>
<td>1</td>
<td>0.000117</td>
</tr>
<tr>
<td>option_category_base</td>
<td>0.000029</td>
<td>1</td>
<td>0.000029</td>
</tr>
<tr>
<td>option_tag_base</td>
<td>0.000027</td>
<td>1</td>
<td>0.000027</td>
</tr>
<tr>
<td>setup_theme</td>
<td>0.000030</td>
<td>1</td>
<td>0.000030</td>
</tr>
<tr>
<td>wp_default_scripts</td>
<td>0.001951</td>
<td>1</td>
<td>0.001951</td>
</tr>
<tr>
<td>set_current_user</td>
<td>0.000114</td>
<td>1</td>
<td>0.000114</td>
</tr>
<tr>
<td>init</td>
<td>0.011603</td>
<td>1</td>
<td>0.011603</td>
</tr>
<tr>
<td>widgets_init</td>
<td>0.003384</td>
<td>1</td>
<td>0.003384</td>
</tr>
<tr>
<td>wp_default_styles</td>
<td>0.000349</td>
<td>1</td>
<td>0.000349</td>
</tr>
<tr>
<td>query_vars</td>
<td>0.000036</td>
<td>1</td>
<td>0.000036</td>
</tr>
<tr>
<td>sanitize_title</td>
<td>0.001518</td>
<td>17</td>
<td>0.000089</td>
</tr>
<tr>
<td>posts_where</td>
<td>0.000033</td>
<td>1</td>
<td>0.000033</td>
</tr>
<tr>
<td>the_posts</td>
<td>0.000127</td>
<td>1</td>
<td>0.000127</td>
</tr>
<tr>
<td>template_redirect</td>
<td>0.000541</td>
<td>1</td>
<td>0.000541</td>
</tr>
<tr>
<td>bloginfo</td>
<td>0.002297</td>
<td>8</td>
<td>0.000287</td>
</tr>
<tr>
<td>term_name</td>
<td>0.000621</td>
<td>2</td>
<td>0.000310</td>
</tr>
<tr>
<td>term_description</td>
<td>0.000982</td>
<td>2</td>
<td>0.000491</td>
</tr>
<tr>
<td>single_post_title</td>
<td>0.000468</td>
<td>2</td>
<td>0.000234</td>
</tr>
<tr>
<td>wp_title</td>
<td>0.000747</td>
<td>2</td>
<td>0.000373</td>
</tr>
<tr>
<td>wp_head</td>
<td>0.020773</td>
<td>1</td>
<td>0.020773</td>
</tr>
<tr>
<td>comments_open</td>
<td>0.000373</td>
<td>4</td>
<td>0.000093</td>
</tr>
<tr>
<td>the_title</td>
<td>0.011747</td>
<td>46</td>
<td>0.000255</td>
</tr>
<tr>
<td>wp_print_styles</td>
<td>0.000175</td>
<td>2</td>
<td>0.000088</td>
</tr>
<tr>
<td>style_loader_src</td>
<td>0.000330</td>
<td>9</td>
<td>0.000037</td>
</tr>
<tr>
<td>wp_print_scripts</td>
<td>0.000440</td>
<td>1</td>
<td>0.000440</td>
</tr>
<tr>
<td>print_scripts_array</td>
<td>0.000050</td>
<td>1</td>
<td>0.000050</td>
</tr>
<tr>
<td>wp_list_pages</td>
<td>0.000305</td>
<td>1</td>
<td>0.000305</td>
</tr>
<tr>
<td>the_author</td>
<td>0.000534</td>
<td>2</td>
<td>0.000267</td>
</tr>
<tr>
<td>the_content</td>
<td>1.004469</td>
<td>1</td>
<td>1.004469</td>
</tr>
<tr>
<td>comment_text</td>
<td>0.001105</td>
<td>1</td>
<td>0.001105</td>
</tr>
<tr>
<td>pings_open</td>
<td>0.000087</td>
<td>1</td>
<td>0.000087</td>
</tr>
<tr>
<td>comment_form</td>
<td>0.007084</td>
<td>1</td>
<td>0.007084</td>
</tr>
<tr>
<td>widget_title</td>
<td>0.001137</td>
<td>4</td>
<td>0.000284</td>
</tr>
<tr>
<td>list_cats</td>
<td>0.004768</td>
<td>22</td>
<td>0.000217</td>
</tr>
<tr>
<td>wp_footer</td>
<td>0.009798</td>
<td>1</td>
<td>0.009798</td>
</tr>
<tr>
<td>wp_print_footer_scripts</td>
<td>0.000115</td>
<td>1</td>
<td>0.000115</td>
</tr>
</tbody>
</table>
<p>Из таблицы видно, что слабое место — это вызов фильтра <code>the_content</code> (вызов более одной секунды), и копать нужно именно в сторону оптимизации фильтров <code>the_content</code>. Пока не поддерживается профилирование каждого обработчика (то есть делаются замеры до вызова первого обработчика <code>the_content</code> и после вызова последнего), но это в планах.</p>
<p>Одна из особенностей плагина — поддержка как WordPress, так и bbPress (правда, пришлось немного поколдовать).</p>
<p>По умолчанию плагин активен только для администратора (WordPress) и Key Master (bbPress); изменить это можно, повесив обработчик на фильтр <code>enable_hook_profiler</code> (должен вернуть <span class="codebox"><code class="php"><span class="kw4">true</span></code></span>, если профайлер нужно активировать и <span class="codebox"><code class="php"><span class="kw4">false</span></code></span> в противном случае).</p>
<p><strong><a href="http://d.sjinks.pro/wordpress/sj-hook-profiler-0.1.zip">Скачать плагин SJ Hook Profiler 0.1</a></strong>.<br />
<strong><a href="http://d.sjinks.pro/wordpress/sj-hook-profiler-0.2.zip">Скачать плагин SJ Hook Profiler 0.2</a></strong>.</p>
<p>© 2012 <a href="http://blog.sjinks.pro">Ars Longa, Vita Brevis</a>. Все права защищены. Перепубликация материалов без разрешения автора запрещена.</p>
<p>При использовании материалов блога наличие активной не закрытой от индексирования ссылки на <a href="http://blog.sjinks.pro/wordpress/plugins/642-sj-hook-profiler/">источник</a> обязательно.</p>]]></content:encoded>
			<wfw:commentRss>http://blog.sjinks.pro/wordpress/plugins/642-sj-hook-profiler/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

