<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="ru"><title type="text">Чтобы не забыть</title><link rel="alternate" type="text/html" href="http://russianpenguin.ru" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/russianpenguin" /><subtitle type="html">Записки на манжетах. Трудовые будни программиста. Проблемы и их решения.</subtitle><updated>2012-02-10T11:59:27+00:00</updated><generator>http://wordpress.org/?v=3.3.1</generator><sy:updatePeriod xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">hourly</sy:updatePeriod><sy:updateFrequency xmlns:sy="http://purl.org/rss/1.0/modules/syndication/">1</sy:updateFrequency><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/russianpenguin" /><feedburner:info uri="russianpenguin" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry><title type="text">PHP: интерфейсы Iterator и IteratorAggregate. Практика применения.</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/PB3zYKB0prY/" /><category term="КОДОшаблоны" /><category term="Полезное" /><category term="Разработка" /><category term="php" /><category term="паттерны" /><category term="практики разработки" /><author><name>Penguin</name></author><updated>2012-02-10T03:59:27-08:00</updated><id>http://russianpenguin.ru/?p=651</id><summary type="html">PHP содержит в себе очень гибгий функционал для реализации коллекций. Базовые элементы - это интерфейсы Iterator и IteratorAggregate. Очень часто разработчики просто не задействуют всю мощь этих средств.</summary><content type="html">&lt;p&gt;Почему в php существует два интерфейса для создания объектов-коллекций, которые можно перебирать при помощи foreach?&lt;br /&gt;
&lt;span id="more-651"&gt;&lt;/span&gt;&lt;br /&gt;
Сначала посмотрим на сами интерфейсы.&lt;br /&gt;
Первый &amp;#8212; это &lt;a href="http://ru.php.net/manual/ru/class.iterator.php" title="Iterator"&gt;Iterator&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="brush:php"&gt;Iterator extends Traversable {
  // получить элемент в текущей позиции
  abstract public mixed current ( void )
  // получить ключ элемента в текущей позиции
  abstract public scalar key ( void )
  // перевести указатель на следующий элемент
  abstract public void next ( void )
  // сбросить положение указателя элемента в начало коллекции
  abstract public void rewind ( void )
  // Проверить, существует ли элемент в текущей позиции
  abstract public boolean valid ( void )
}&lt;/pre&gt;
&lt;p&gt;Теперь второй интерфейс &amp;#8212; &lt;a href="http://ru.php.net/manual/ru/class.iteratoraggregate.php" title="IteratorAggregate"&gt;IteratorAggregate&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="brush:php"&gt;IteratorAggregate extends Traversable {
  // получить внешний итератор
  abstract public Traversable getIterator ( void )
}&lt;/pre&gt;
&lt;p&gt;Оба интерфейса являются наследниками &lt;a href="http://www.php.net/manual/ru/class.traversable.php" title="Интерфейс traversable. PHP-manual"&gt;Traversable&lt;/a&gt;. Этот интерфейс сигнализирует о том, что реализующий его объект является коллекцией и может выступать в качестве источника данных в цикле foreach.&lt;/p&gt;
&lt;p&gt;Как их использовать?&lt;br /&gt;
Сначала Iterator.&lt;/p&gt;
&lt;pre class="brush:php"&gt;class simple_iterator implements Iterator {
    private $position = 0;
    private $array = array(
        1,2,3,4,5,6,7,8,9
    );

    public function __construct() {
        $this-&amp;gt;position = 0;
    }

    function rewind() {
        $this-&amp;gt;position = 0;
    }

    function current() {
        return $this-&amp;gt;array[$this-&amp;gt;position];
    }

    function key() {
        return $this-&amp;gt;position;
    }

    function next() {
        $this-&amp;gt;position++;
    }

    function valid() {
        return isset($this-&amp;gt;array[$this-&gt;position]);
    }
}

$it = new simple_iterator;

foreach($it as $key =&amp;gt; $value) {
    echo $key. " ". $value;
    echo "\n";
}&lt;/pre&gt;
&lt;pre&gt;$ php iterator.php
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9&lt;/pre&gt;
&lt;p&gt;Что-то тут не так? Верно? Внутри коллекции обычный массив. Который всегда можно перебрать в цикле foreach. А мы вынуждены реализовывать кучу методов для поддержания функционала.&lt;/p&gt;
&lt;p&gt;Упростить? Запросто!&lt;br /&gt;
Интерфейс &lt;a href="http://ru.php.net/manual/ru/class.iteratoraggregate.php" title="IteratorAggregate"&gt;IteratorAggrerate&lt;/a&gt; &amp;#8212; позволяет использовать уже имеющиеся механизмы перебора коллекций.&lt;/p&gt;
&lt;pre class="brush:php"&gt;class simple_iterator implements IteratorAggregate {
    private $array = array(
        1,2,3,4,5,6,7,8,9
    );

    function getIterator()
    {
        return new ArrayIterator($this-&amp;gt;array);
    }
}

$it = new simple_iterator;

foreach($it as $key =&amp;gt; $value) {
    echo $key. " ". $value;
    echo "\n";
}&lt;/pre&gt;
&lt;pre&gt;$ php iteratoraggregate.php
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9&lt;/pre&gt;
&lt;p&gt;Просто? Просто.&lt;br /&gt;
На этом примере очень хорошо видно, что применение IteratorAggregate оправдано тогда, когда в основу коллекции положена структура данных уже имеющая механизм перебора.&lt;/p&gt;
&lt;p&gt;Нельзя реализовать оба интерфейса одновременно.&lt;/p&gt;
&lt;p&gt;Вообще тема итераторов очень многогранна. Большинство книг либо вообще ее не затрагивают, либо описывают только &lt;a href="http://ru.php.net/manual/ru/class.arrayiterator.php" title="ArrayIterator"&gt;ArrayIterator&lt;/a&gt;.&lt;br /&gt;
Хотя php содержит в себе целое &lt;a href="http://ru.php.net/manual/ru/spl.iterators.php" title="PHP-SPL: семейство итераторов"&gt;семейство&lt;/a&gt; итераторов. Например итератор, кеширующий результаты обхода другого итератора &amp;#8212; &lt;a href="http://ru.php.net/manual/ru/class.cachingiterator.php" title="CachingIterator"&gt;CachingIterator&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="brush:php"&gt;class simple_iterator implements Iterator {
    private $position = 0;
    private $array = array(
        1,2,3,4,5,6,7,8,9
    );

    public function __construct() {
        $this-&amp;gt;position = 0;
    }

    function rewind() {
        $this-&amp;gt;position = 0;
    }

    function current() {
        // тут мы делаем что-то очень-очень важное
        sleep(1);
        return $this-&amp;gt;array[$this-&amp;gt;position];
    }

    function key() {
        return $this-&amp;gt;position;
    }

    function next() {
        $this-&amp;gt;position++;
    }

    function valid() {
        return isset($this-&amp;gt;array[$this-&amp;gt;position]);
    }
}

$it = new simple_iterator;
$cache = new CachingIterator($it, CachingIterator::FULL_CACHE);

$start_time = time();
foreach($cache as $key =&amp;gt; $value) {
    echo $key. " ". $value;
    echo "\n";
}
echo "time: ".(time() - $start_time)."\n";

$start_time = time();
foreach($cache-&amp;gt;getCache() as $key =&amp;gt; $value) {
    echo $key. " ". $value;
    echo "\n";
}
echo "time: ".(time() - $start_time)."\n";&lt;/pre&gt;
&lt;pre&gt;$ php cacheiterator.php
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
time: 9
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
time: 0&lt;/pre&gt;
&lt;p&gt;Быстро, эффективно, полезно.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://php.net/manual" title="Руководство по PHP"&gt;Источник&lt;/a&gt;.&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/21/php-%d0%bb%d0%b5%d0%bd%d0%b8%d0%b2%d1%8b%d0%b5-%d0%b2%d1%8b%d1%87%d0%b8%d1%81%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f/" rel="bookmark" title="21.01.2012"&gt;PHP: ленивые вычисления&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/28/php-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%bd%d0%b0%d0%b1%d0%bb%d1%8e%d0%b4%d0%b0%d1%82%d0%b5%d0%bb%d1%8c-observer/" rel="bookmark" title="28.01.2012"&gt;PHP: паттерн наблюдатель (observer)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/11/24/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu-soxranenie-dannyx/" rel="bookmark" title="24.11.2010"&gt;jqGrid: API для взаимодействия с серверной частью &amp;#8212; сохранение данных&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/05/03/tdd-poisk-naimenshego-obshhego-kratnogo-dlya-neskolkix-chisel/" rel="bookmark" title="03.05.2010"&gt;TDD: Поиск наименьшего общего кратного для нескольких чисел&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2009/11/21/php-pravilnoe-primenenie-setterov/" rel="bookmark" title="21.11.2009"&gt;PHP: Правильное применение сеттеров&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 97.466 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/PB3zYKB0prY" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2012/02/10/php-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b-iterator-%d0%b8-iteratoraggregate-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://russianpenguin.ru/2012/02/10/php-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b-iterator-%d0%b8-iteratoraggregate-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0/</feedburner:origLink></entry><entry><title type="text">PHP: как правильно обрабатывать массивы</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/bUQS6WcqBbI/" /><category term="Just for Fun" /><category term="Полезное" /><category term="Разработка" /><category term="highload" /><category term="php" /><author><name>Penguin</name></author><updated>2012-02-09T10:43:52-08:00</updated><id>http://russianpenguin.ru/?p=637</id><summary type="html">Насколько эффективны встроенные функции обработки массивов php вроде array_walk или array_map? И почему разработчики так бояться их использовать?</summary><content type="html">&lt;p&gt;Сегодня у меня появился очень интересный повод понять, насколько эффективны различные способы вызова функций в php и как эффективнее обрабатывать массивы.&lt;br /&gt;
Все дело в том, что в php есть несколько встроенных функций для обработки массивов. Многие почему-то их не используют. Хотя код получается более эффективным (речь идет об экономии стотысячных долей секунды на обработку элементов. &lt;img src='http://russianpenguin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;  И еще он получается более логичным. Хотя это лично мое мнение.&lt;br /&gt;
Итак. Попробуем оценить эффективность работы функций обработки массивов и накладные расходы, затрачиваемые на вызов функций различными способами.&lt;br /&gt;
&lt;span id="more-637"&gt;&lt;/span&gt;&lt;br /&gt;
Подопытными функциями стали:&lt;/p&gt;
&lt;p&gt;Обычная функция&lt;/p&gt;
&lt;pre class="brush:php"&gt;function test($a)
{
	return $a+2;
}&lt;/pre&gt;
&lt;p&gt;Функция внутри пространства имен&lt;/p&gt;
&lt;pre class="brush:php"&gt;namespace test1;
function test($a)
{
	return $a+2;
}&lt;/pre&gt;
&lt;p&gt;Статический метод класса&lt;/p&gt;
&lt;pre class="brush:php"&gt;class test2
{
	static function test($a)
	{
		return $a+2;
	}
}&lt;/pre&gt;
&lt;p&gt;Метод объекта&lt;/p&gt;
&lt;pre class="brush:php"&gt;class test3
{
	function test($a)
	{
		return $a+2;
	}
}

$test_class = new test3;
$test_class-&amp;gt;test($a);&lt;/pre&gt;
&lt;p&gt;Лямбда-функция как значение переменно&lt;/p&gt;
&lt;pre class="brush:php"&gt;$test_func = function($a)
{
	return $a+2;
};&lt;/pre&gt;
&lt;p&gt;Непосредственно передаваемая лямбда-функция&lt;/p&gt;
&lt;pre class="brush:php"&gt;function($a){return $a+2;}&lt;/pre&gt;
&lt;p&gt;Первое испытание &amp;#8212; это использование обычного цикла foreach для обработки массива размером 1000000 элементов.&lt;br /&gt;
Испытание было разбито на две секции:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Обработка значений без сохранения результатов&lt;/li&gt;
&lt;li&gt;Сохранение результатов, возвращаемых функцией в тестовый массив&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В свою очередь каждый этап был разбит на два маленьких этапа:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;В первом случае вызов функции производился непосредственно&lt;/li&gt;
&lt;li&gt;Во втором &amp;#8212; через &lt;span style="text-decoration: line-through;"&gt;жопу&lt;/span&gt; вызов при помощи call_user_func&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Результаты сведены в табличку&lt;/p&gt;
&lt;table width="605" border="0" cellspacing="0" cellpadding="0"&gt;
&lt;colgroup&gt;
&lt;col width="141" /&gt;
&lt;col span="4" width="116" /&gt; &lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;" rowspan="3" width="141" height="81"&gt;Тип подопытной функции&lt;/td&gt;
&lt;td style="text-align: center;" colspan="4" width="464"&gt;тип перебора&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;" colspan="2" width="232" height="20"&gt;без сохранения&lt;/td&gt;
&lt;td style="text-align: center;" colspan="2" width="232"&gt;с сохранением&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;" width="116" height="41"&gt;foreach&lt;/td&gt;
&lt;td style="text-align: center;" width="116"&gt;call_user_func inside foreach&lt;/td&gt;
&lt;td style="text-align: center;" width="116"&gt;foreach&lt;/td&gt;
&lt;td style="text-align: center;" width="116"&gt;call_user_func inside foreach&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000005&lt;/td&gt;
&lt;td align="right"&gt;0,000011&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000013&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;test1\test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000005&lt;/td&gt;
&lt;td align="right"&gt;0,000012&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;td align="right"&gt;0,000014&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;test2::test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;td align="right"&gt;0,000013&lt;/td&gt;
&lt;td align="right"&gt;0,000008&lt;/td&gt;
&lt;td align="right"&gt;0,000015&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;$test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000005&lt;/td&gt;
&lt;td align="right"&gt;0,000011&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;td align="right"&gt;0,000012&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;$test_class-&amp;gt;test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;td align="right"&gt;0,000015&lt;/td&gt;
&lt;td align="right"&gt;0,000008&lt;/td&gt;
&lt;td align="right"&gt;0,000016&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;И график&lt;br /&gt;
&lt;a href="http://russianpenguin.ru/wp-content/uploads/2012/02/2012-02-09_22-11_Microsoft-Excel.jpg"&gt;&lt;img class="aligncenter size-medium wp-image-641" title="Обработка массива при помощи foreach" src="http://russianpenguin.ru/wp-content/uploads/2012/02/2012-02-09_22-11_Microsoft-Excel-300x204.jpg" alt="" width="300" height="204" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Выводы? Вывод только один использование call_user_func и call_user_func_array практически в два с половиной раза увеличивает время работы приложения. Если вы обрабатываете более сотни тысяч значений, то стоит от нее отказаться. И вообще использовании подобных методов очень редко является необходимостью. И чаще обозначает плохой дизайн системы.&lt;/p&gt;
&lt;p&gt;Теперь второе испытание: использование встроенных функций по обработке массивов.&lt;br /&gt;
Принимали участие:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;array_map&lt;/li&gt;
&lt;li&gt;array_map + сохранение результирующего массива&lt;/li&gt;
&lt;li&gt;array_walk&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Что из этого получилось можно посмотреть в табличке результатов забега.&lt;/p&gt;
&lt;table width="489" border="0" cellspacing="0" cellpadding="0"&gt;
&lt;colgroup&gt;
&lt;col width="141" /&gt;
&lt;col span="3" width="116" /&gt; &lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: center;" rowspan="2" width="141" height="65"&gt;перелаваемая функция&lt;/td&gt;
&lt;td style="text-align: center;" colspan="3" width="348"&gt;тип функции-итератора&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center;" width="116" height="45"&gt;array_map&lt;/td&gt;
&lt;td style="text-align: center;" width="116"&gt;array_map и сохранение&lt;/td&gt;
&lt;td style="text-align: center;" width="116"&gt;array_walk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;test1\test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;test2::test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;td align="right"&gt;0,000005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;$test_class-&amp;gt;test($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;$test_func($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td height="20"&gt;lambda function($a)&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000007&lt;/td&gt;
&lt;td align="right"&gt;0,000006&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;И график.&lt;br /&gt;
&lt;a href="http://russianpenguin.ru/wp-content/uploads/2012/02/2012-02-09_22-22_Microsoft-Excel.jpg"&gt;&lt;img src="http://russianpenguin.ru/wp-content/uploads/2012/02/2012-02-09_22-22_Microsoft-Excel-300x214.jpg" alt="" title="Обход массивов встроенными функциями php" width="300" height="214" class="aligncenter size-medium wp-image-643" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Что можно сказать?&lt;br /&gt;
Не стоит бояться использовать обход массивов при помощи встроенных функций. Они даже быстрее, нежели обработка при помощи foreach.&lt;br /&gt;
Многие ругают встроенные функции php, называя порядок аргументов нелогичным. Возможно.&lt;br /&gt;
Хотя для array_map: применить(функцию, [к]массиву). Для array_walk: обойти(массив, функцией). Простое правило для запоминания.&lt;/p&gt;
&lt;p&gt;И еще array_map выделяет объем памяти для хранения результирующего массива еще до фактического запуска.&lt;/p&gt;
&lt;p&gt;Что больше всего меня удивило &amp;#8212; так это то, что обращение к функции внутри namespace почти всегда немного дороже, нежели обращение к остальным функциям. Хотя можно списать на погрешность вычислений.&lt;br /&gt;
Исходники можно скачать &lt;a href="demo.russianpenguin.ru/files/work_with_php_arrays.zip" title="Бенчмарк встроенных функций php для обработки массивов"&gt;отсюда&lt;/a&gt;.&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/21/php-%d0%bb%d0%b5%d0%bd%d0%b8%d0%b2%d1%8b%d0%b5-%d0%b2%d1%8b%d1%87%d0%b8%d1%81%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f/" rel="bookmark" title="21.01.2012"&gt;PHP: ленивые вычисления&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/28/php-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%bd%d0%b0%d0%b1%d0%bb%d1%8e%d0%b4%d0%b0%d1%82%d0%b5%d0%bb%d1%8c-observer/" rel="bookmark" title="28.01.2012"&gt;PHP: паттерн наблюдатель (observer)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/05/03/tdd-poisk-naimenshego-obshhego-kratnogo-dlya-neskolkix-chisel/" rel="bookmark" title="03.05.2010"&gt;TDD: Поиск наименьшего общего кратного для нескольких чисел&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/02/10/php-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b-iterator-%d0%b8-iteratoraggregate-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0/" rel="bookmark" title="10.02.2012"&gt;PHP: интерфейсы Iterator и IteratorAggregate. Практика применения.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/11/24/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu-soxranenie-dannyx/" rel="bookmark" title="24.11.2010"&gt;jqGrid: API для взаимодействия с серверной частью &amp;#8212; сохранение данных&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 13.149 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/bUQS6WcqBbI" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2012/02/09/php-%d0%ba%d0%b0%d0%ba-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d1%8c%d0%bd%d0%be-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%b0%d1%82%d1%8b%d0%b2%d0%b0%d1%82%d1%8c-%d0%bc%d0%b0%d1%81%d1%81%d0%b8%d0%b2%d1%8b/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://russianpenguin.ru/2012/02/09/php-%d0%ba%d0%b0%d0%ba-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d1%8c%d0%bd%d0%be-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%b0%d1%82%d1%8b%d0%b2%d0%b0%d1%82%d1%8c-%d0%bc%d0%b0%d1%81%d1%81%d0%b8%d0%b2%d1%8b/</feedburner:origLink></entry><entry><title type="text">Консоль mysql: форматирование вывода</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/x26depUc39E/" /><category term="Web-разработка" /><category term="Полезное" /><category term="mysql" /><author><name>Penguin</name></author><updated>2012-02-05T08:23:03-08:00</updated><id>http://russianpenguin.ru/?p=627</id><summary type="html">Удобный консольный модификатор для выводов в клиенте mysql результата запроса вертикально</summary><content type="html">&lt;p&gt;&lt;a href="http://russianpenguin.ru/wp-content/uploads/2012/02/2012-02-05_20-19_penguin@mysql2.jpg"&gt;&lt;img src="http://russianpenguin.ru/wp-content/uploads/2012/02/2012-02-05_20-19_penguin@mysql2-300x98.jpg" alt="" title="Модификатор вертикального вывода результатов" width="300" height="98" class="alignleft size-medium wp-image-629" /&gt;&lt;/a&gt;Неожиданно. Копался в документации и совершенно случайно обнаружил очень удобный модификатор, который позволяет выводить результаты запроса вертикально.&lt;/p&gt;
&lt;p&gt;Модификатор &lt;strong&gt;\G&lt;/strong&gt;&lt;br /&gt;
&lt;span id="more-627"&gt;&lt;/span&gt;&lt;br /&gt;
Действует в консольном клиенте mysql.&lt;/p&gt;
&lt;pre class="brush:sql"&gt;mysql&amp;gt;select * from func\G&lt;/pre&gt;
&lt;p&gt;Получаем вывод в виде&lt;/p&gt;
&lt;pre&gt;*************************** 1. row ***************************
name: preg_capture
 ret: 0
  dl: lib_mysqludf_preg.so
type: function
*************************** 2. row ***************************
name: preg_check
 ret: 2
  dl: lib_mysqludf_preg.so
type: function
*************************** 3. row ***************************
name: preg_position
 ret: 2
  dl: lib_mysqludf_preg.so
type: function
*************************** 4. row ***************************
name: preg_replace
 ret: 0
  dl: lib_mysqludf_preg.so
type: function
*************************** 5. row ***************************
name: preg_rlike
 ret: 2
  dl: lib_mysqludf_preg.so
type: function
*************************** 6. row ***************************
name: lib_mysqludf_preg_info
 ret: 0
  dl: lib_mysqludf_preg.so
type: function
6 rows in set (0.02 sec)&lt;/pre&gt;
&lt;p&gt;Удобно &lt;img src='http://russianpenguin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt; &lt;/p&gt;
&lt;p&gt;&lt;a href="http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html" title="Команды консольного клиента mysql"&gt;Источник&lt;/a&gt;.&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/15/jquery-%d0%b0%d0%bd%d0%b0%d1%82%d0%be%d0%bc%d0%b8%d1%8f-%d1%81%d0%be%d0%b1%d1%8b%d1%82%d0%b8%d0%b9/" rel="bookmark" title="15.01.2012"&gt;jQuery: анатомия событий&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/27/mysql-%d0%b3%d0%b5%d0%bd%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d1%8f-%d0%b8%d1%81%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b9/" rel="bookmark" title="27.01.2012"&gt;MySQL: генерация исключений.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/09/23/mysql-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b0-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba/" rel="bookmark" title="23.09.2011"&gt;MySQL: обработка ошибок&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2009/08/18/mysql-generaciya-sluchajnyx-strok/" rel="bookmark" title="18.08.2009"&gt;MySQL: генерация случайных строк&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/05/05/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu/" rel="bookmark" title="05.05.2010"&gt;jqGrid: API для взаимодействия с серверной частью&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 29.133 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/x26depUc39E" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2012/02/05/%d0%ba%d0%be%d0%bd%d1%81%d0%be%d0%bb%d1%8c-mysql-%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b2%d1%8b%d0%b2%d0%be%d0%b4%d0%b0/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://russianpenguin.ru/2012/02/05/%d0%ba%d0%be%d0%bd%d1%81%d0%be%d0%bb%d1%8c-mysql-%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b2%d1%8b%d0%b2%d0%be%d0%b4%d0%b0/</feedburner:origLink></entry><entry><title type="text">PHP: паттерн наблюдатель (observer)</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/OM6kFP0JN-g/" /><category term="КОДОшаблоны" /><category term="Разработка" /><category term="php" /><category term="шаблоны" /><author><name>Penguin</name></author><updated>2012-01-28T07:35:47-08:00</updated><id>http://russianpenguin.ru/?p=583</id><summary type="html">Паттерн "наблюдатель" позволяет избавить систему от нарушения принципов "открытости-закрытости". Реализовать сквозную функциональность. И ускорить кодирование проекта.</summary><content type="html">&lt;p&gt;Как часто нам приходится реализовывать сквозную функциональность? Часто! Очень и очень часто. А как сделать так, чтобы эта функциональность была реализована корректно?&lt;/p&gt;
&lt;div class="reference" style="border:dotted;padding:10px;color:black;background-color:wheat;"&gt;Сквозной (в терминах ООП) называют функциональность, которая не может быть выделена в отдельную сущность. Примером может быть логгирование событий, проверка прав доступа и т.п.&lt;/div&gt;
&lt;p&gt;Если мы не может выделить подобный функционал в отдельную сущность, то мы можем смягчить последствия внедрения подобного функционала.&lt;br /&gt;
Первым шагом станет выделение этого функцонала в отдельную сущность, которая каким-либо образом будет анализировать события. Для реализации подобных вещей лучше всего подходит паттерн наблюдатель (observer).&lt;br /&gt;
&lt;span id="more-583"&gt;&lt;/span&gt;&lt;br /&gt;
В чем преимущество паттерна? Он позволяет нескольким объектам системы неявно наблюдать за состоянием другого объекта. Т.е. если состояние наблюдаемого объекта изменяется, то объекты налблюдатели получают уведомление об изменении состояния.&lt;br /&gt;
Лучше всего понять данный паттерн на примере логгирования событий. Представим, что у нас есть некоторая сущность, действия которой мы просто обязаны сохранять где-нибудь.&lt;br /&gt;
У нас есть база данных. У нас есть memcache.&lt;br /&gt;
Топорным способом реализации будет расковырять объект и в каждое действие этого объекта вписать функционал по сохранинию записи в лог.&lt;/p&gt;
&lt;pre class="brush:php"&gt;class object
{
  function save_log($message)
  {
    //тут код по сохранению сообщения в базу
    echo $message."\n";
  }

  function action_one()
  {
    $this-&amp;gt;save_log('start action one');
  }

  function action_two()
  {
    $this-&amp;gt;save_log('start action two');
  }
}&lt;/pre&gt;
&lt;p&gt;Пробуем.&lt;/p&gt;
&lt;pre class="brush:php"&gt;$object = new object();
$object-&amp;gt;action_one();
$object-&amp;gt;action_two();&lt;/pre&gt;
&lt;p&gt;Вообще нормально.&lt;/p&gt;
&lt;pre&gt;~$ php simple.php
start action one
start action two&lt;/pre&gt;
&lt;p&gt;Вроде все работает, но остается много маленьких нюансов.&lt;br /&gt;
Теперь у нас появляется второй объект. Он тоже требует логирования. Чтобы не повторять куски кода мы вынесем этот функционал в отдельный класс.&lt;/p&gt;
&lt;pre class="brush:php"&gt;class logger
{
  function save_log($message)
  {
    //тут код по сохранению сообщения в базу
    echo $message."\n";
  }
}

class object1
{
  private $log = null;

  function __construct()
  {
    $this-&gt;log = new logger();
  }

  function action_one()
  {
    $this-&amp;gt;log-&amp;gt;save_log('start action one from '.__CLASS__);
  }

  function action_two()
  {
    $this-&amp;gt;log-&amp;gt;save_log('start action two from '.__CLASS__);
  }
}

class object2
{
  private $log = null;

  function __construct()
  {
    $this-&gt;log = new logger();
  }

  function action_one()
  {
    $this-&amp;gt;log-&amp;gt;save_log('start action one from '.__CLASS__);
  }

  function action_two()
  {
    $this-&amp;gt;log-&amp;gt;save_log('start action two from '.__CLASS__);
  }
}&lt;/pre&gt;
&lt;p&gt;Пробуем.&lt;/p&gt;
&lt;pre class="brush:php"&gt;$object1 = new object1();
$object1-&amp;gt;action_one();
$object1-&amp;gt;action_two();

$object2 = new object2();
$object2-&amp;gt;action_one();
$object2-&amp;gt;action_two();&lt;/pre&gt;
&lt;pre&gt;$ php simple2.php
start action one from object1
start action two from object1
start action one from object2
start action two from object2
&lt;/pre&gt;
&lt;p&gt;Вроде бы все. Как прилежные разработчики мы можем сделать для классов object1 и object2 общего предка, который инициализирует логгер. Мы можем превратить логгера в синглтон.&lt;br /&gt;
Но тут возникает кошмар любого разработчика. Нам нужно:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Добавить логгирование не только на консоль, но и в базу данных, сервер syslog и иже&lt;/li&gt;
&lt;li&gt;Сделать так, чтобы каждый объект логгировал события в разные источники.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Почему это кошмар? Для первого требования мы можем поменять логгер, добавив в него нужные механизмы логгирования. Для второго случая мы можем сделать несколько функций. И вызывать эти функции в объектах. Что то-вроде:&lt;/p&gt;
&lt;pre class="brush:php"&gt;log_to_database($message);
log_to_console($message)&lt;/pre&gt;
&lt;p&gt;Но это неправильно. Эти решения отнимают очень много времени на поддержание кода, на то, чтобы найти, где расположен нужный кусок кода. На то, чтобы просто ввести новый функционал.&lt;/p&gt;
&lt;p&gt;Одна из основных проблем &amp;#8212; это нарушения принципа &amp;#171;открытия-закрытия&amp;#187; (OCP)&lt;/p&gt;
&lt;div class="reference" style="border:dotted;padding:10px;color:black;background-color:wheat;"&gt;Принцип &amp;#171;открытия-закрытия&amp;#187; (OCP) означает, что объект (класс или функция) должен быть закрыт для изменения, но открыт для расширения. &lt;a href="http://www.oodesign.com/open-close-principle.html" title="Причина нарушения принципа &amp;quot;открытия-закрытия&amp;quot; (OCP)" style="color:blue;"&gt;Пример.&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;И как это починить? Применить паттерн &amp;#171;наблюдатель&amp;#187;, который решает практически все проблемы, что были описаны выше.&lt;/p&gt;
&lt;div style="text-align:center;"&gt;&lt;a href="http://www.oodesign.com/images/design_patterns/behavioral/observer_implementation_-_uml_class_diagram.gif" title="UML-диаграмма паттерна &amp;quot;наблюдатель&amp;quot;" class="fancybox"&gt;&lt;img style="width:500px;" src="http://www.oodesign.com/images/design_patterns/behavioral/observer_implementation_-_uml_class_diagram.gif" title="UML-диаграмма паттерна &amp;quot;наблюдатель&amp;quot;" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Сначала рассмотрим объект события, который будет передаваться от наблюдаемого объекта к наблюдающим.&lt;/p&gt;
&lt;pre class="brush:php"&gt;/**
 * Класс, описывающий событие.
 */
class Observer_Event
{
	/**
	 * @var string $message Сообщеине событиы
	 */
	private $message = '';

	/**
	 * Набор ключ-&gt;значение. Ключ будет замещаться значением при выводе $message
	 * @var array $value
	 */
	private $values = array();

	/**
	 * Сохраняет в событии мообщение и набор замещающих параметров
	 *
	 * @param $message
	 * @param array $values
	 */
	function __construct($message, $values = array())
	{
		$this-&amp;gt;message = $message;
		$this-&amp;gt;values = $values;
	}

	/**
	 * Преобразование сообщения в строку для вывода
	 * @return string
	 */
	function __toString()
	{
		return __($this-&amp;gt;message, $this-&amp;gt;values);
	}
}&lt;/pre&gt;
&lt;p&gt;Поскольку в качестве фреймворка использовалась kohanа, то грех не воспользоваться функцией локализации &lt;b&gt;__&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Использовать сообщение очень просто.&lt;/p&gt;
&lt;pre class="brush:php"&gt;$event = new Observer_Event("message with content \":value\"", array(':value' =&gt; "some content"))
echo $event;&lt;/pre&gt;
&lt;p&gt;Получим&lt;/p&gt;
&lt;pre&gt;php event_test.php
message with content "some content"&lt;/pre&gt;
&lt;p&gt;Теперь перейдем к реализации наблюдаемого объекта&lt;/p&gt;
&lt;pre class="brush:php"&gt;/**
 * Реоализация добавления и удаления наблюдателей.
 */
class Observer_Observable
{
	const EVENT_ALL = 0;

	/**
	 * @var array $observers Стек наблюдателей
	 */
	private $observers = array();

	/**
	 * Возвращает код события по его имени
	 *
	 * Пример использования: ObservableClass::event("eventtype")
	 *
	 * @static
	 * @param $type
	 * @return mixed
	 */
	static function event($type)
	{
		$event_name = classname(self)."::EVENT_".strtoupper($type);
		return constant($event_name);
	}

	/**
	 * Добавление наблюдателя в список.
	 * Выполняет проверку на дублирование элементов.
	 *
	 * Возвращает ссылку на класс для реализации цепочек
	 *
	 * @param observer $observer Объект наблюдатель
	 * @param integer $event_type тип наблюдаемого события
	 * @return $this
	 */
	function attach(Observer_Observer $observer, $event_type = EVENT_ALL)
	{
		$this-&gt;observers[$event_type][] = $observer;
		return $this;
	}

	/**
	 * Передача события всем существующим наблюдателям
	 *
	 * @param $type Тип генерируемого сообщения
	 * @param Observer_Event $event сообщение
	 */
	function fire($type, Observer_Event $event)
	{
		$mapped_func = function(Observer_Observer $observer) use ($event)
		{
			$observer-&gt;fire($event);
		};
		//fire custom event
		array_map($mapped_func, Arr::get($this-&gt;observers, $type, array()));

		//fire event to EVENT_ALL listeners (if type is not event_all)
		if(self::EVENT_ALL != $type)
		{
			array_map($mapped_func, Arr::get($this-&gt;observers, self::EVENT_ALL, array()));
		}
	}
}&lt;/pre&gt;
&lt;p&gt;Ничего сложного. Регистрируются наблюдатели. Каждый наблюдатель может отслеживать либо все события (&lt;b&gt;EVENT_ALL&lt;/b&gt;), либо события, которые объявлены наблюдаемым объектом.&lt;/p&gt;
&lt;p&gt;Остался наблюдатель.&lt;/p&gt;
&lt;pre class="brush:php"&gt;/**
 * Реализация паттерна observer
 */
abstract class Observer_Observer
{
	/**
	 * Обработка события наблюдаемного объекта
	 *
	 * @abstract
	 * @param Observer_Event $event
	 */
	abstract function fire(Observer_Event $event);
}&lt;/pre&gt;
&lt;p&gt;Абстрактный класс, который содержит обработчик события.&lt;br /&gt;
И теперь собираем все воедино&lt;/p&gt;
&lt;pre class="brush:php"&gt;class logger extends Observer_Observer
{
	function fire(Observer_Event $event)
	{
		//тут код по сохранению сообщения в базу
		echo $event."\n";
	}
}

class object1 extends Observer_Observable
{
	function action_one()
	{
		$this-&amp;gt;fire(self::EVENT_ALL, new Observer_Event('start action :method from :class',
			array(
				':class' =&amp;gt; __CLASS__,
				':method' =&amp;gt; __METHOD__,
			)
		));
	}

	function action_two()
	{
		$this-&amp;gt;fire(self::EVENT_ALL, new Observer_Event('start action :method from :class',
			array(
				':class' =&amp;gt; __CLASS__,
				':method' =&amp;gt; __METHOD__,
			)
		));
	}
}

class object2 extends Observer_Observable
{
	function action_one()
	{
		$this-&amp;gt;fire(self::EVENT_ALL, new Observer_Event('start action :method from :class',
			array(
				':class' =&amp;gt; __CLASS__,
				':method' =&amp;gt; __METHOD__,
			)
		));
	}

	function action_two()
	{
		$this-&amp;gt;fire(self::EVENT_ALL, new Observer_Event('start action :method from :class',
			array(
				':class' =&amp;gt; __CLASS__,
				':method' =&amp;gt; __METHOD__,
			)
		));
	}
}&lt;/pre&gt;
&lt;p&gt;Запускаем&lt;/p&gt;
&lt;pre class="brush:php"&gt;$observer = new logger();

$object1 = new object1();
$object1-&amp;gt;attach($observer);
$object1-&amp;gt;action_one();
$object1-&amp;gt;action_two();

$object2 = new object2();
$object2-&amp;gt;action_one();
$object2-&amp;gt;action_two();&lt;/pre&gt;
&lt;p&gt;И получаем.&lt;/p&gt;
&lt;pre&gt;start action object1::action_one from object1
start action object1::action_two from object1&lt;/pre&gt;
&lt;p&gt;Следует заметить, что к объекту $object2 мы логгер не подключали. А следовательно на экран ничего и не было выведено.&lt;/p&gt;
&lt;p&gt;Источники:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.oodesign.com" title="Принциры объектно-ориентированного дизайна"&gt;http://www.oodesign.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="www.books.ru/books/priemy-obektno-orientirovannogo-proektirovaniya-352130/?partner=361738" title="Приемы объектно-ориентированного проектирования. Паттерны проектирования "&gt;Приемы объектно-ориентированного проектирования. Паттерны проектирования&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="www.books.ru/books/bystraya-razrabotka-programm-printsipy-primery-praktika-147550/?partner=361738" title="Быстрая разработка программ. Практика"&gt;Быстрая разработка программ: принципы, примеры, практика&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/11/24/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu-soxranenie-dannyx/" rel="bookmark" title="24.11.2010"&gt;jqGrid: API для взаимодействия с серверной частью &amp;#8212; сохранение данных&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/21/php-%d0%bb%d0%b5%d0%bd%d0%b8%d0%b2%d1%8b%d0%b5-%d0%b2%d1%8b%d1%87%d0%b8%d1%81%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f/" rel="bookmark" title="21.01.2012"&gt;PHP: ленивые вычисления&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/02/10/php-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b-iterator-%d0%b8-iteratoraggregate-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0/" rel="bookmark" title="10.02.2012"&gt;PHP: интерфейсы Iterator и IteratorAggregate. Практика применения.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/05/05/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu/" rel="bookmark" title="05.05.2010"&gt;jqGrid: API для взаимодействия с серверной частью&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2009/07/02/pearauth-primer-ispolzovaniya/" rel="bookmark" title="02.07.2009"&gt;PEAR::Auth &amp;#8212; пример использования&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 19.684 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/OM6kFP0JN-g" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2012/01/28/php-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%bd%d0%b0%d0%b1%d0%bb%d1%8e%d0%b4%d0%b0%d1%82%d0%b5%d0%bb%d1%8c-observer/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">2</slash:comments><feedburner:origLink>http://russianpenguin.ru/2012/01/28/php-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%bd%d0%b0%d0%b1%d0%bb%d1%8e%d0%b4%d0%b0%d1%82%d0%b5%d0%bb%d1%8c-observer/</feedburner:origLink></entry><entry><title type="text">MySQL: генерация исключений.</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/IgMWIgPJJ_w/" /><category term="Web-разработка" /><category term="КОДОшаблоны" /><category term="mysql" /><author><name>Penguin</name></author><updated>2012-01-27T10:07:53-08:00</updated><id>http://russianpenguin.ru/?p=586</id><summary type="html">Начиная с версии 5,5 в mysql появились расширенные механизмы обработки ошибок и их генерации. В статье рассказывается, как пользоваться новым функционалом.</summary><content type="html">&lt;p&gt;&lt;a href="http://russianpenguin.ru/wp-content/uploads/2011/07/logo-mysql-110x57.png"&gt;&lt;img src="http://russianpenguin.ru/wp-content/uploads/2011/07/logo-mysql-110x57.png" alt="" title="mysql logo" width="110" height="57" class="alignleft size-full wp-image-455" /&gt;&lt;/a&gt;Ранее я писал об &lt;a href="http://russianpenguin.ru/2011/09/23/mysql-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b0-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba/" title="Обработка ошибок в mysql"&gt;обработке ошибок&lt;/a&gt;. Вот только одна проблема: генерировать исключения нам никто не давал. Можно их было только перехватывать.&lt;br /&gt;
С появлением MySQL 5.5 появилась возможность генерировать собственные исключения. А так же пробрасывать перехваченные исключения после отлова их handler&amp;#8217;ами.&lt;br /&gt;
Кратко рассмотрим возможности, которые отдали в наше распоряжение.&lt;br /&gt;
&lt;span id="more-586"&gt;&lt;/span&gt;&lt;br /&gt;
Проброс исключений&lt;/p&gt;
&lt;p&gt;Небольшой пример.&lt;/p&gt;
&lt;pre class="brush:php"&gt;try {
  $a = 10/0;
} catch (Exception $e) {
  write_log("На ноль делить нельзя"):
  throw $e;
}&lt;/pre&gt;
&lt;p&gt;Перехваченное исключение выбрасывается в систему вновь.&lt;br /&gt;
В mysql у нас есть отличная вещь: resignal. (А поскольку в mysql деление на 0 дает null, то напишем процедуру, выбирающую несуществющие данные)&lt;/p&gt;
&lt;pre class="brush:sql"&gt;delimiter | ;
create procedure select_magic()
begin
  declare _a int default null;
  declare exit handler for sqlexception
  begin
    select "this message print from exit handler" as `message`;
    resignal;
  end;
  select * from `test`;
end|&lt;/pre&gt;
&lt;p&gt;И вот что мы увидим:&lt;/p&gt;
&lt;pre&gt;mysql&amp;gt; call select_magic();
+--------------------------------------+
| message                              |
+--------------------------------------+
| this message print from exit handler |
+--------------------------------------+
1 row in set (0.00 sec)

ERROR 1146 (42S02): Table 'test.test' doesn't exist
mysql&amp;gt; show errors;
+-------+------+---------------------------------+
| Level | Code | Message                         |
+-------+------+---------------------------------+
| Error | 1146 | Table 'test.test' doesn't exist |
| Error | 1146 | Table 'test.test' doesn't exist |
+-------+------+---------------------------------+
2 rows in set (0.00 sec)&lt;/pre&gt;
&lt;p&gt;А теперь посмотрим, что могло быть в случае отсутствия resignal.&lt;/p&gt;
&lt;pre class="brush:sql"&gt;delimiter | ;
create procedure select_magic_2()
begin
  declare _a int default null;
  declare exit handler for sqlexception
  begin
    select "this message print from exit handler (without resignal)" as `message`;
  end;
  select * from `test`;
end|&lt;/pre&gt;
&lt;pre&gt;mysql&amp;gt; call select_magic_2();
+---------------------------------------------------------+
| message                                                 |
+---------------------------------------------------------+
| this message print from exit handler (without resignal) |
+---------------------------------------------------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql&amp;gt; show errors;
+-------+------+---------------------------------+
| Level | Code | Message                         |
+-------+------+---------------------------------+
| Error | 1146 | Table 'test.test' doesn't exist |
+-------+------+---------------------------------+
1 row in set (0.00 sec)&lt;/pre&gt;
&lt;p&gt;Почему в первом случае мы выдим две ошибки а во втором только одну?&lt;br /&gt;
Все просто: resignal берет последнее исключение из диагностического стека. И дублирует его.&lt;br /&gt;
Важно, что в случае отсутствия активных handler&amp;#8217;ов resignal работать не будет. Происходит это потому, что на вершине стека ошибок может лежать необработанное исключение. Тогда смысл resignal теряется.&lt;/p&gt;
&lt;p&gt;На примере это выглядит так.&lt;/p&gt;
&lt;pre class="brush:sql"&gt;delimiter | ;
create procedure foo()
begin
  resignal;
end|

create procedure bar()
begin
  declare exit handler for sqlexception
  begin
    select "bar procedure" as `message`;
    call foo();
  end;
  select * from `test`;
end|&lt;/pre&gt;
&lt;p&gt;А теперь посмотрим. Сначала попробуем вызвать resignal без активных обработчиков, а потом с одним обработчиком.&lt;/p&gt;
&lt;pre&gt;mysql&amp;gt; call foo();
ERROR 1645 (0K000): RESIGNAL when handler not active
mysql&amp;gt; show errors;
+-------+------+----------------------------------+
| Level | Code | Message                          |
+-------+------+----------------------------------+
| Error | 1645 | RESIGNAL when handler not active |
+-------+------+----------------------------------+
1 row in set (0.00 sec)

mysql&amp;gt; call bar();
+---------------+
| message       |
+---------------+
| bar procedure |
+---------------+
1 row in set (0.00 sec)

ERROR 1146 (42S02): Table 'test.test' doesn't exist
mysql&amp;gt; show errors;
+-------+------+---------------------------------+
| Level | Code | Message                         |
+-------+------+---------------------------------+
| Error | 1146 | Table 'test.test' doesn't exist |
| Error | 1146 | Table 'test.test' doesn't exist |
+-------+------+---------------------------------+
2 rows in set (0.00 sec)&lt;/pre&gt;
&lt;p&gt;Как видно из примера, resignal не обязательно должен быть объявлен внутри хендлера. Достаточно, чтобы где-то выше по стеку вывозов был установлен хендлер.&lt;/p&gt;
&lt;p&gt;Выше мы рассматривали самый простейший вариант resignal &amp;#8212; вариант, который просто дублирует последнюю ошибку в стеке.&lt;br /&gt;
Всего же разновидностей resignal три:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Простой (рассмотрен ранее)&lt;/p&gt;
&lt;pre&gt;RESIGNAL&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Изменяющий информацию об ошибке (можно изменить код ошибки или сообщение об ошибке)
&lt;pre&gt;RESIGNAL SET signal_information_item [, signal_information_item] ...&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Меняющий класс исключения (Изменяет тип ошибки)
&lt;pre&gt;RESIGNAL condition_value
SET signal_information_item [, signal_information_item] ...&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Чтобы изменить диагностическое сообщение или код ошибки можно воспользоваться вторым типом.&lt;/p&gt;
&lt;pre class="brush:sql"&gt;delimiter | ;
create procedure resignal_change_info()
begin
  declare _a int default null;
  declare exit handler for sqlexception
  begin
    select "simple message" as `message`;
    resignal set mysql_errno = 12000;
  end;
  select * from `test`;
end|&lt;/pre&gt;
&lt;pre&gt;mysql&amp;gt; call resignal_change_info();
+----------------+
| message        |
+----------------+
| simple message |
+----------------+
1 row in set (0.00 sec)

ERROR 12000 (42S02): Table 'test.test' doesn't exist
mysql&amp;gt; show errors;
+-------+-------+---------------------------------+
| Level | Code  | Message                         |
+-------+-------+---------------------------------+
| Error |  1146 | Table 'test.test' doesn't exist |
| Error | 12000 | Table 'test.test' doesn't exist |
+-------+-------+---------------------------------+
2 rows in set (0.00 sec)&lt;/pre&gt;
&lt;p&gt;Третий тип позволяет изменять тип ошибки (о типе ошибок ниже)&lt;/p&gt;
&lt;pre class="brush:sql"&gt;delimiter | ;
create procedure resignal_change_condition()
begin
  declare _a int default null;
  declare exit handler for sqlexception
  begin
    select "simple message" as `message`;
    resignal sqlstate '01000' set mysql_errno = 12000;
  end;
  select * from `test`;
end|&lt;/pre&gt;
&lt;pre&gt;mysql&amp;gt; call resignal_change_condition();
+----------------+
| message        |
+----------------+
| simple message |
+----------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected, 2 warnings (0.00 sec)

mysql&amp;gt; show errors;
+-------+------+---------------------------------+
| Level | Code | Message                         |
+-------+------+---------------------------------+
| Error | 1146 | Table 'test.test' doesn't exist |
+-------+------+---------------------------------+
1 row in set (0.00 sec)

mysql&amp;gt; show warnings;
+---------+-------+---------------------------------+
| Level   | Code  | Message                         |
+---------+-------+---------------------------------+
| Error   |  1146 | Table 'test.test' doesn't exist |
| Warning | 12000 | Table 'test.test' doesn't exist |
+---------+-------+---------------------------------+
2 rows in set (0.00 sec)&lt;/pre&gt;
&lt;p&gt;Что вообще произошло? Почему на вершине стека ошибок не появилась новая ошибка?&lt;br /&gt;
А все просто &lt;b&gt;sqlstate &amp;#8217;01000&amp;#8242;&lt;/b&gt; понизил класс ошибки с error до warning. И она не вызвала необходимости обработки.&lt;/p&gt;
&lt;p&gt;Теперь о классах ошибок.&lt;br /&gt;
SQLSTATE &amp;#8212; это пять цифр. Первые две обозначают класс состояния. Остальные три произвольные и характеризуют определенный тип состояния внутри класса.&lt;br /&gt;
Различают несколько типов состояний. ПО первым двум цифрам.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00 &amp;#8212; успешное завершение. Недопустимо для ручной генерации&lt;/li&gt;
&lt;li&gt;01 &amp;#8212; warning. пишется в лог, но не мешает дальнейшей работе&lt;/li&gt;
&lt;li&gt;02 &amp;#8212; not found. если его не обработать, то исполнение завершается&lt;/li&gt;
&lt;li&gt;&amp;gt;02 &amp;#8212; exception. класс исключений&lt;/li&gt;
&lt;li&gt;40 &amp;#8212; стандартные исключения.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ладно. Пробрасывать научились. А генерировать как?&lt;br /&gt;
Есть механизм signal&lt;/p&gt;
&lt;pre&gt;SIGNAL condition_value
    [SET signal_information_item
    [, signal_information_item] ...]

condition_value:
    SQLSTATE [VALUE] sqlstate_value
  | condition_name

signal_information_item:
    condition_information_item_name = simple_value_specification

condition_information_item_name:
    CLASS_ORIGIN
  | SUBCLASS_ORIGIN
  | MESSAGE_TEXT
  | MYSQL_ERRNO
  | CONSTRAINT_CATALOG
  | CONSTRAINT_SCHEMA
  | CONSTRAINT_NAME
  | CATALOG_NAME
  | SCHEMA_NAME
  | TABLE_NAME
  | COLUMN_NAME
  | CURSOR_NAME&lt;/pre&gt;
&lt;pre class="brush:sql"&gt;delimiter | ;
create procedure mysignal()
begin
  signal sqlstate '03000' set message_text = 'first signal';
end|&lt;/pre&gt;
&lt;pre&gt;mysql&amp;#038;gt call mysignal();
ERROR 1644 (03000): first signal&lt;/pre&gt;
&lt;p&gt;Будет правильным предположить, что signal способен работать не только с событиями прописанными при помощи sqlstate, но и с событиями, которые были объявлены при помощи declare condition.&lt;/p&gt;
&lt;p&gt;Источник: &lt;a href="http://dev.mysql.com/doc/refman/5.5/en/condition-handling.html" title="Обработка ошибок в mysql - официальное руководство"&gt;http://dev.mysql.com/doc/refman/5.5/en/condition-handling.html&lt;/a&gt;&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/09/23/mysql-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%ba%d0%b0-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba/" rel="bookmark" title="23.09.2011"&gt;MySQL: обработка ошибок&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/09/12/mysql-%d1%86%d0%b8%d0%ba%d0%bb%d1%8b-%d0%b2-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d0%bc%d1%8b%d1%85-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d0%b4%d1%83%d1%80%d0%b0%d1%85/" rel="bookmark" title="12.09.2011"&gt;MySQL: циклы в хранимых процедурах&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/02/09/php-%d0%ba%d0%b0%d0%ba-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d1%8c%d0%bd%d0%be-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%b0%d1%82%d1%8b%d0%b2%d0%b0%d1%82%d1%8c-%d0%bc%d0%b0%d1%81%d1%81%d0%b8%d0%b2%d1%8b/" rel="bookmark" title="09.02.2012"&gt;PHP: как правильно обрабатывать массивы&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2009/08/18/mysql-generaciya-sluchajnyx-strok/" rel="bookmark" title="18.08.2009"&gt;MySQL: генерация случайных строк&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2009/08/22/php-rabota-s-xml/" rel="bookmark" title="22.08.2009"&gt;PHP: работа с XML&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 10.539 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/IgMWIgPJJ_w" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2012/01/27/mysql-%d0%b3%d0%b5%d0%bd%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d1%8f-%d0%b8%d1%81%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b9/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://russianpenguin.ru/2012/01/27/mysql-%d0%b3%d0%b5%d0%bd%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d1%8f-%d0%b8%d1%81%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b9/</feedburner:origLink></entry><entry><title type="text">PHP: ленивые вычисления</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/rX6OsfsYQB0/" /><category term="КОДОшаблоны" /><category term="Разработка" /><category term="php" /><category term="ленивые вычисления" /><author><name>Penguin</name></author><updated>2012-01-21T08:16:42-08:00</updated><id>http://russianpenguin.ru/?p=579</id><summary type="html">Очень часто при разработки проектов мы сталкиваемся с ситуацией, когда неизвестно, потребуются ли данные в дальнейшем или нет. Примером может быть логирование каких-либо событий.
Почему бы не вычислять данные тогда, когда это действительно необходимо?</summary><content type="html">&lt;p&gt;Очень часто при разработки проектов мы сталкиваемся с ситуацией, когда неизвестно, потребуются ли данные в дальнейшем или нет. Примером может быть логирование каких-либо событий.&lt;br /&gt;
Почему бы не вычислять данные тогда, когда это действительно необходимо?&lt;br /&gt;
Для этого я написал собственный велосипед, реализующий механизм отложенных вычислений подобно haskell.&lt;br /&gt;
&lt;span id="more-579"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Итак. Класс Callback_Deferred&lt;/p&gt;
&lt;pre class="brush:php"&gt;/**
 * Механизм отложенного вызова
 *
 * Требуется, если нужно отложить вызов функции до момента реальной необходимости.
 * К примеру объект может вообще не затребовать вызов.
 */
class Callback_Deferred
{
	/**
	 * Callback-функция
	 * @var null
	 */
	private $func = null;

	/**
	 * Массив аргументов функции
	 * @var null
	 */
	private $args = null;

	/**
	 * Создание объектов отложенного вызова
	 * Возвращает объект отложенного вызова
	 *
	 * @static
	 * @param callback $func функция отложенного вызова
	 * @param array $args аргументы функции отложенного вызова
	 * @return Call_Deferred
	 */
	static function factory($func, $args)
	{
		return new self($func, $args);
	}

	/**
	 * Конструирование объекта отложенного вызова
	 *
	 * @param callback $func функция отложенного вызова
	 * @param array $args аргументы функции отложенного вызова
	 */
	private function __construct($func, $args)
	{
		$this-&amp;gt;func = $func;
		$this-&amp;gt;args = $args;
	}

	/**
	 * Преобразование результатов отложенного вызова в строку
	 * Фозможен только если функция возвращает тип string
	 * В противном случае будет выброшено исключение
	 *
	 * @return string
	 */
	public function __toString()
	{
		try
		{
			return (string)call_user_func_array($this-&amp;gt;func, $this-&amp;gt;args);
		}
		catch(Exception $e)
		{
			return '';
		}
	}

	/**
	 * Непосредственный вызов функции так,
	 * словно это был бы обычный вызов вида func_name($arg1, $arg2,  ...)
	 *
	 * @return mixed
	 */
	public function __invoke()
	{
		return call_user_func_array($this-&amp;gt;func, $this-&amp;gt;args);
	}
}&lt;/pre&gt;
&lt;p&gt;Теперь проверим этот механизм&lt;/p&gt;
&lt;pre class="brush:php"&gt;
/**
 * Функция, выполняющая очень долгие вычисления с $param
 * @param integer $param
 * @return результат вычислений
 */
$func = function($param)
{
  //long calculation
  sleep(1);
  return $param;
};

/**
 * Класс-агрегатор
 */
class log
{
  private $container;

  static private $instance = null;

  static function instance()
  {
    if( ! self::$instance)
    {
      self::$instance = new self();
    }
    return self::$instance;
  }

  function push($value)
  {
    $this-&amp;gt;container[] = $value;
  }

  private function __construct()
  {
  }

  public function out()
  {
    array_map(function($value){
      echo $value."\n";
    },$this-&amp;gt;container);
  }
}
//начинаем основной цикл вычислений
echo date("d/m/y : H:i:s:", time())." start\n";

//выволняем вычисления над некоторыми данными и добавляем в стек функцию печати лога
array_map(function($int){
        global $func;
        log::instance()-&gt;push(Callback_Deferred::factory($func, array($int)));
}, range(1,100));

echo date("d/m/y : H:i:s:", time())." end\n";
//Приступаем к выводу лога
echo date("d/m/y : H:i:s:", time())." start log out\n";
log::instance()-&amp;gt;out();
echo date("d/m/y : H:i:s:", time())." end log out\n";&lt;/pre&gt;
&lt;p&gt;И получаем вывод в консоль:&lt;/p&gt;
&lt;pre&gt;$php callback.php
21/01/12 : 15:58:28: start
21/01/12 : 15:58:28: end
21/01/12 : 15:58:28: start log out
1
2
3
4
5
6
7
8
//много букв
97
98
99
100
21/01/12 : 16:00:08: end log out&lt;/pre&gt;
&lt;p&gt;Очевидно, что при непосредственно выволнении функции $func мы бы тормозили основные вычисления. В то же время результаты $func нам не нужны &amp;#171;здесь и сейчас&amp;#187;. Поэтому логично выполнять эту функцию только тогда, когда данные необходимы.&lt;br /&gt;
Вот и все.&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/28/php-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%bd%d0%b0%d0%b1%d0%bb%d1%8e%d0%b4%d0%b0%d1%82%d0%b5%d0%bb%d1%8c-observer/" rel="bookmark" title="28.01.2012"&gt;PHP: паттерн наблюдатель (observer)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/02/10/php-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b-iterator-%d0%b8-iteratoraggregate-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0/" rel="bookmark" title="10.02.2012"&gt;PHP: интерфейсы Iterator и IteratorAggregate. Практика применения.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/05/03/tdd-poisk-naimenshego-obshhego-kratnogo-dlya-neskolkix-chisel/" rel="bookmark" title="03.05.2010"&gt;TDD: Поиск наименьшего общего кратного для нескольких чисел&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/11/24/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu-soxranenie-dannyx/" rel="bookmark" title="24.11.2010"&gt;jqGrid: API для взаимодействия с серверной частью &amp;#8212; сохранение данных&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/02/09/php-%d0%ba%d0%b0%d0%ba-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d1%8c%d0%bd%d0%be-%d0%be%d0%b1%d1%80%d0%b0%d0%b1%d0%b0%d1%82%d1%8b%d0%b2%d0%b0%d1%82%d1%8c-%d0%bc%d0%b0%d1%81%d1%81%d0%b8%d0%b2%d1%8b/" rel="bookmark" title="09.02.2012"&gt;PHP: как правильно обрабатывать массивы&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 13.593 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/rX6OsfsYQB0" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2012/01/21/php-%d0%bb%d0%b5%d0%bd%d0%b8%d0%b2%d1%8b%d0%b5-%d0%b2%d1%8b%d1%87%d0%b8%d1%81%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://russianpenguin.ru/2012/01/21/php-%d0%bb%d0%b5%d0%bd%d0%b8%d0%b2%d1%8b%d0%b5-%d0%b2%d1%8b%d1%87%d0%b8%d1%81%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f/</feedburner:origLink></entry><entry><title type="text">jQuery: анатомия событий</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/jvYH3iGHkuw/" /><category term="Web-разработка" /><category term="jQuery" /><category term="события" /><author><name>Penguin</name></author><updated>2012-01-15T03:23:26-08:00</updated><id>http://russianpenguin.ru/?p=572</id><summary type="html">Анатомия реализации событий в библиотеке jquery. Или почему смешивать несколько библиотек в одном проекте - неправильный подход.</summary><content type="html">&lt;p&gt;Изначально статья предполагала, что будет описано простое создание чекбокса &amp;#171;выделить все&amp;#187; на базе jquery, но в итоге получился разбор реализации событий javascript в jquery.&lt;br /&gt;
А все потому, что очень часто на форумах появляются вопросы вроде: &amp;#171;а как же оно устроено&amp;#187;? И остаются без ответа.&lt;/p&gt;
&lt;p&gt;Итак ТЗ: нужно сделать табличку, где в каждой строке есть чекбокс и чекбокс, который позволяет снять/поставить выделение на всех строках таблицы.&lt;/p&gt;
&lt;p&gt;&lt;span id="more-572"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('input.check_all').click(function(event){
  $('input.flags:checked').attr('checked',$(this).is(':checked'));
});&lt;/pre&gt;
&lt;p&gt;Вот. Просто!&lt;/p&gt;
&lt;p&gt;А теперь у нас новый проект и новое ТЗ: на каждый чекбокс нужно повесить событие, которое как-то реагирует на нажатие этого самого чекбокса.&lt;br /&gt;
Например меняет уровень прозрачности чекбокса &amp;#171;выделить все&amp;#187; или еще что-нибудь.&lt;/p&gt;
&lt;p&gt;Сначала пишем обработчики для элементов .flags (Это которые в строках)&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('input.flags').click(function(event){
  var name = $(this).attr('name');
  var check_info = ($(this).is(':checked'))?'выбран':'не выбран';
  say('checkbox '+name+', состояние: '+check_info);
});&lt;/pre&gt;
&lt;p&gt;Теперь нам надо добавить обработчик нажатия для той самой кнопки, которая должна включать и выключать все.&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('input.check_all').click(function(event){
  $('input.flags').attr('checked',$(this).is(':checked');
});&lt;/pre&gt;
&lt;p&gt;Не работает. Обработчик события при ручной установке атрибута не вызывается.&lt;br /&gt;
А что если мы будем генерировать событие клик так, словно это пользователь нажал на чекбокс?&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('input.check_all').click(function(event){
  var flag = $(this).is(':checked')?':not(:checked)':':checked';
  $('input.flags'+flag).trigger('click');
});&lt;/pre&gt;
&lt;p&gt;После проверки в нескольких браузерах видно, что поведения данного кода не совсем корректно.&lt;br /&gt;
События срабатывают не в том порядке, в каком должны.&lt;/p&gt;
&lt;p&gt;В jquery есть triggerhandler() &amp;#8212; функция вызывает обработчики события, установленные пользователем, но не вызывает браузерный обработчик.&lt;br /&gt;
Но  при попытке использования нас ждет сюрприз &amp;#8212; она срабатывает только для первого элемента в обернутом наборе.&lt;/p&gt;
&lt;p&gt;Т.е. если мы сделаем&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('input.related[type=checkbox]').triggerHandler('click');&lt;/pre&gt;
&lt;p&gt;мы увидим только один алерт.Чтобы заставить эту функцию работать для всех элементов надо воспользоваться прямым перебором при помощи each.&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('input.check_all').click(function(event){
  var flag = $(this).is(':checked')?':not(:checked)':':checked';
  var new_state = $(this).is(':checked');
  $('input.flags'+flag).each(function(){
    $(this).attr('checked',new_state);
    $(this).triggerHandler('click');
  });
});&lt;/pre&gt;
&lt;p&gt;Работает &lt;img src='http://russianpenguin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;&lt;br /&gt;
Теперь неприятный сюрприз: triggerHandler не работает с событиями, которые установлены при помощи live&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('input.flags').live('click',function(event){
  var name = $(this).attr('name');
  var check_info = ($(this).is(':checked'))?'выбран':'не выбран';
  say('checkbox '+name+', состояние: '+check_info);
});&lt;/pre&gt;
&lt;p&gt;Если обработчик установлен таким образом, то tiggerHandler Вам не поможет.&lt;br /&gt;
Для таких случаев можно вызвать обработчик более экстравагантным способом: запретить всплытие события по dom-дереву. Тем самым мы избавляемся от проблем с неработающими обработчиками.&lt;/p&gt;
&lt;p&gt;Почему все это происходит? Неизвестно?&lt;/p&gt;
&lt;p&gt;Напишем простой пример:&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;$('#toggle_flag').click(function(event){
  $('input.flags').trigger('click');
});
$('input.flags').each(function(){
  this.addEventListener('click',function(){
    var name = $(this).attr('name');
    var check_info = ($(this).is(':checked'))?'выбран':'не выбран';
    say('checkbox '+name+', состояние при всплытии: '+check_info);
  },false);
  this.addEventListener('click',function(){
    var name = $(this).attr('name');
    var check_info = ($(this).is(':checked'))?'выбран':'не выбран';
    say('checkbox '+name+', состояние при захвате: '+check_info);
  },true);
});&lt;/pre&gt;
&lt;p&gt;И этот пример работает.&lt;/p&gt;
&lt;p&gt;Но почему?&lt;/p&gt;
&lt;p&gt;Рассмотрим код &lt;img src='http://russianpenguin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;&lt;br /&gt;
Нас интересует функция trigger (строки 2846-2976)&lt;/p&gt;
&lt;p&gt;Ниже представлен урезанный код с комментариями, описывающими работу функции.&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;trigger: function( event, data, elem, onlyHandlers ) {
     // 2848-2888: тут идет подготовка данных и получение очереди обработчиков
     // Об очереди обработчиков более подробно описано дальше

     // 2891-2904: глобальный обработчик событий

     // 2907-2909: не вызываем обработчик на текстовых нодах и на комментариях
     // 2919-2927: cur - это текущий элемент
     var cur = elem,
          // IE doesn't like method names with a colon (#3533, #8272)
          ontype = type.indexOf(":") &lt; 0 ? "on" + type : "";

     // 2924-2940: Вызываем обработчик элемента,
     // а затем эмулируем фазу всплытия события
     // обработка заканчивается если мы дойдем до корня DOM,
     // либо если обработчик выполнит event.stopPropagnation()
     do {
          var handle = jQuery._data( cur, "handle" );

          event.currentTarget = cur;
          if ( handle ) {
               handle.apply( cur, data );
          }

          // Вызываем инлайн-обработчики
          // (которые были установлены при помощи конструкций вида onclick="")
          if ( ontype &amp;#038;&amp;#038; jQuery.acceptData( cur ) &amp;#038;&amp;#038; cur[ ontype ] &amp;#038;&amp;#038; cur[ ontype ].apply( cur, data ) === false ) {
               event.result = false;
               event.preventDefault();
          }

          // Эмулируем фазу всплытия
          cur = cur.parentNode || cur.ownerDocument || cur === event.target.ownerDocument &amp;#038;&amp; window;
     } while ( cur &amp;#038;&amp;#038; !event.isPropagationStopped() );

     // 2943-2973: если ни один из обработчиков не остановил распространение события,
     // то вызываем браузерный обработчик
     if ( !event.isDefaultPrevented() ) {
          var old,
               special = jQuery.event.special[ type ] || {};
          // Если событие не "special" и не клик по ссылке
          if ( (!special._default || special._default.call( elem.ownerDocument, event ) === false) &amp;#038;&amp;#038;
               !(type === "click" &amp;#038;&amp;#038; jQuery.nodeName( elem, "a" )) &amp;#038;&amp;#038; jQuery.acceptData( elem ) ) {
               // То пробуев вызвать браузерный обработчик
               try {
                    if ( ontype &amp;#038;&amp;#038; elem[ type ] ) {
                         // Создаем замещение для инлайн методов (чтобы не вызвать повторно
                         old = elem[ ontype ];

                         if ( old ) {
                              elem[ ontype ] = null;
                         }

                         // Глобальная переменная, предотвращающая повторный вызов обработчика
                         jQuery.event.triggered = type;
                         // Вызываем браузерный обработчик
                         elem[ type ]();
                    }
               } catch ( ieError ) {}
               // Возврат замещения для инлайн-скриптов
               if ( old ) {
                    elem[ ontype ] = old;
               }
               // сброс флага
               jQuery.event.triggered = undefined;
          }
     }

     return event.result;
}&lt;/pre&gt;
&lt;p&gt;А теперь кратко о том, что же мы тут видим.&lt;br /&gt;
На данный момент браузеры не поддерживают непосредственный вызов событий из скриптов (при помощи какой-нибудь triggerevent), поэтому jquery просто реализует такой функционал с нуля.&lt;br /&gt;
Находится элемент, для которого планируется вызвать событие; вызывается обработчик события и эмулируется фаза всплытия.&lt;br /&gt;
И только после всего этого вызывается событие браузера.&lt;br /&gt;
Это и объясняет, почему галочка на чекбоксе изменялась после того, как сработал хук.&lt;br /&gt;
Мало того, если вы добавляли к элементу свои обработчики при помощи addEventListener, то они могут не сработать если какой-то из обработчиков jquery остановил баблинг эвента.&lt;/p&gt;
&lt;p&gt;И еще нас заинтересует функция add объекта jQuery.event, которая привязывает обработчик события непосредственно к элементу.&lt;br /&gt;
Ниже выдержки из этой функции&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;// 2590: объявление функции
add: function( elem, types, handler, data ) {
     // 2591-2612: выполняется проверка входных аргументов
     // и создание уникального идентификатора обработчика
     // (если его нет)

// 2615: получаем данные для элемента (обертка над jQuery.data)
     var elemData = jQuery._data( elem );
     // 2623: получаем функцию-обработчик jquery для элемента
     var events = elemData.events,
          eventHandle = elemData.handle;

     // 2626-2628: список событий, обработчики которых установлены у элемента
     if ( !events ) {
          elemData.events = events = {};
     }

     // 2630-2638: для каждого элемента создается единственный (!) обработчик
     // который "слушает" все события элемента
     if ( !eventHandle ) {
          elemData.handle = eventHandle = function( e ) {
               // Discard the second event of a jQuery.event.trigger() and
               // when an event is called after a page has unloaded
               return typeof jQuery !== "undefined" &amp;#038;&amp;#038; (!e || jQuery.event.triggered !== e.type) ?
               jQuery.event.handle.apply( eventHandle.elem, arguments ) :
               undefined;
          };
     }

     // 2642-2648: обработка множества событий
     // например обработка случая bind("mouseup mousedown")

     while ( (type = types[ i++ ]) ) {
          // 2651-2653: любой обработчик - это объект: функция и данные
          // тут обрабатывается преобразование функции в объекты
          handleObj = handleObjIn ?
               jQuery.extend({}, handleObjIn) :
               { handler: handler, data: data };

          // 2656-2664: обработка неймспейсов
          handleObj.type = type;
          if ( !handleObj.guid ) {
               handleObj.guid = handler.guid;
          }

          // 2672-2673: получаем список обработчиков события event у элемента
          var handlers = events[ type ],
               special = jQuery.event.special[ type ] || {};

          // 2676-2691: инициализируем очередь обработчиков событий
          // (если ее еще нет)
          if ( !handlers ) {
               handlers = events[ type ] = [];

               // тут надо сказать, что такое "special events" в терминологии jquery
               // Это события live, ready, beforeunload
               // Эти события должны быть обработаны особым образом
               if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
                    // 2684-2689: добавление глобального "слушателя" событий,
                    // который был объявлен выше
                    if ( elem.addEventListener ) {
                         elem.addEventListener( type, eventHandle, false );

                    } else if ( elem.attachEvent ) {
                         elem.attachEvent( "on" + type, eventHandle );
                    }
               }
          }

          // 2693-2699: обработка special events

          // 2702: добавляем устанавливаемый обработчик события в очередь обработчиков
          handlers.push( handleObj );

          // 2705: сигнализируем, что для определенного типа события есть обработчики
          // нужно для оптимизации работы
          jQuery.event.global[ type ] = true;
     }

     // ... все остальное
}&lt;/pre&gt;
&lt;p&gt;Просматривая эту функцию становится понятно, что jquery абстрагирует от нативных событий браузера.&lt;br /&gt;
Кратко:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;на каждый тип собитыя у элемента создается глобальный обработчик jquery,&lt;/li&gt;
&lt;li&gt;каждый пользовательский обработчик попадает в очередь обработки,&lt;/li&gt;
&lt;li&gt;при появлении события срабатывает обработчик jquery и вызывает все пользовательские обработчики.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Выводы: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;как и всякая универсальная библиотека jquery не лишена недостатков,&lt;/li&gt;
&lt;li&gt;если вы используете jquery, то лучше никогда не смешивать подходы к работе с событиями (поясню: не использовать нативную установку событый и установку при помощи jquery).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ну а как же triggerHandler, спросите вы?&lt;/p&gt;
&lt;p&gt;Так все просто&lt;/p&gt;
&lt;p&gt;Четвертый аргумент функции trigger как раз и означает, что нужно выполнить останов распространения события.&lt;/p&gt;
&lt;pre class="brush:javascript"&gt;triggerHandler: function( type, data ) {
     if ( this[0] ) {
          return jQuery.event.trigger( type, data, this[0], true );
     }
}&lt;/pre&gt;
&lt;p&gt;Да. Но как же событие live с которым не работает triggerHandler?&lt;br /&gt;
Тоже ничего сложного live-события - это трансформация обычного события в события вида live.&lt;eventName&gt;.&lt;br /&gt;
Соответственно на него заводится новый обработчик, привязанный к корню документа. Фазы всплытия при triggerHandler нет. Поэтому и обработчик не срабатывает.&lt;/p&gt;
&lt;p&gt;Да. И теперь вы будете знать, почему выделение галочки при генерации события происходит позже, чем срабатывают обработчики click. &lt;img src='http://russianpenguin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;&lt;br /&gt;
Кстати, отличная иллюстрация того, почему лучше не смешивать в своих проектах разные фреймворки.&lt;/p&gt;
&lt;p&gt;З.Ы.: для изучения использовался jquery версии 1.6.3&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/04/27/179/" rel="bookmark" title="27.04.2010"&gt;jQuery: Чекбоксы и выбор строк в таблице&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/04/08/jquery-otlichiya-mezhdu-append-i-appendto/" rel="bookmark" title="08.04.2010"&gt;jQuery: отличия между append и appendTo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/02/05/%d0%ba%d0%be%d0%bd%d1%81%d0%be%d0%bb%d1%8c-mysql-%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b2%d1%8b%d0%b2%d0%be%d0%b4%d0%b0/" rel="bookmark" title="05.02.2012"&gt;Консоль mysql: форматирование вывода&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/28/php-%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd-%d0%bd%d0%b0%d0%b1%d0%bb%d1%8e%d0%b4%d0%b0%d1%82%d0%b5%d0%bb%d1%8c-observer/" rel="bookmark" title="28.01.2012"&gt;PHP: паттерн наблюдатель (observer)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/05/05/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu/" rel="bookmark" title="05.05.2010"&gt;jqGrid: API для взаимодействия с серверной частью&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 18.182 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/jvYH3iGHkuw" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2012/01/15/jquery-%d0%b0%d0%bd%d0%b0%d1%82%d0%be%d0%bc%d0%b8%d1%8f-%d1%81%d0%be%d0%b1%d1%8b%d1%82%d0%b8%d0%b9/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">2</slash:comments><feedburner:origLink>http://russianpenguin.ru/2012/01/15/jquery-%d0%b0%d0%bd%d0%b0%d1%82%d0%be%d0%bc%d0%b8%d1%8f-%d1%81%d0%be%d0%b1%d1%8b%d1%82%d0%b8%d0%b9/</feedburner:origLink></entry><entry><title type="text">Java, PhpStorm, ActiveDirectory, перенаправление папок и проблема запуска</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/96MurAxu_9Q/" /><category term="Soft" /><category term="java" /><category term="phpstorm" /><category term="trouble" /><category term="windows" /><author><name>Penguin</name></author><updated>2011-12-19T09:24:27-08:00</updated><id>http://russianpenguin.ru/?p=565</id><summary type="html">Проблема работы java-приложений при включенном перенаправлении папок в домене. Или почему phpstorm ругается на заблокированные файлы.</summary><content type="html">&lt;p&gt;Как-то вечером я запустил PhpStorm на свежей windows 7, которая была введена в мой домашний домен. В домене настроено перенаправление папок пользователя на самба-сервер (не перемещаемые профили, а именно перенаправление отдельных папок).&lt;br /&gt;
И что же получилось? PhpStorm запустился только один раз. После он в упор отказывался запускаться ссылаясь на то, что файлы в .WebIde10\system\caches заблокированы для записи. Странно.&lt;br /&gt;
&lt;span id="more-565"&gt;&lt;/span&gt;&lt;br /&gt;
Оказалось, что &lt;a href="http://bugs.sun.com/view_bug.do?bug_id=4787931" title="System property "user.home" does not correspond to "USERPROFILE" (win) "&gt;багу&lt;/a&gt; в jvm уже почти 10 лет. Суть его в том, что содержимое внутренней переменной user.home вовсе не равно содержимому %USERPROFILE%.&lt;br /&gt;
Проверить это можно простым кодом&lt;/p&gt;
&lt;pre class="brush:java"&gt;public class PropertyTest{
  public static void main(String[] args) {
    System.out.println(System.getProperty("user.home"));
  }
}&lt;/pre&gt;
&lt;p&gt;В моем случае это выглядело так:&lt;/p&gt;
&lt;pre&gt;C:\projects&gt;java PropertyTest
\\samba\profiles\penguin

C:\projects&gt;echo %userprofile%
C:\Users\penguin&lt;/pre&gt;
&lt;p&gt;Печально &lt;img src='http://russianpenguin.ru/wp-includes/images/smilies/icon_sad.gif' alt=':(' class='wp-smiley' /&gt; &lt;/p&gt;
&lt;p&gt;Покопавшись в конфиге phpstorm (C:\Program Files (x86)\JetBrains\PhpStorm 3.0\bin\idea.properties) можно найти интересные строки&lt;/p&gt;
&lt;pre&gt;# Uncomment to disable Safe Write feature, which causes permission change on editing a (e.g. Samba-) mounted files.
#----------------------------------------------------------------------
#idea.no.safe.write=true&lt;/pre&gt;
&lt;p&gt;Раскомментировали и все работает как надо (только предварительно нужно снести папку .WebIde10 с шары. поскольку блокировки на запись там остались).&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/12/18/windows-7-%d0%bd%d0%b5-%d1%83%d1%85%d0%be%d0%b4%d0%b8%d1%82-%d0%b2-%d1%81%d0%bf%d1%8f%d1%89%d0%b8%d0%b9-%d1%80%d0%b5%d0%b6%d0%b8%d0%bc-%d0%b0%d0%b2%d1%82%d0%be%d0%bc%d0%b0%d1%82%d0%be%d0%bc/" rel="bookmark" title="18.12.2011"&gt;Windows 7 автоматически не уходит в спящий режим&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/02/20/%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-xls-%d1%81%d1%80%d0%b5%d0%b4%d1%81%d1%82%d0%b2%d0%b0%d0%bc%d0%b8-php/" rel="bookmark" title="20.02.2011"&gt;Создание XLS средствами PHP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2009/08/18/windows-7-problemy-c-setyu/" rel="bookmark" title="18.08.2009"&gt;Windows 7: проблемы c сетью&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/07/22/svn-init-d-%d1%81%d0%ba%d1%80%d0%b8%d0%bf%d1%82-%d0%b4%d0%bb%d1%8f-debian/" rel="bookmark" title="22.07.2011"&gt;svn: init.d скрипт для debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/01/21/php-%d0%bb%d0%b5%d0%bd%d0%b8%d0%b2%d1%8b%d0%b5-%d0%b2%d1%8b%d1%87%d0%b8%d1%81%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f/" rel="bookmark" title="21.01.2012"&gt;PHP: ленивые вычисления&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 18.840 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/96MurAxu_9Q" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2011/12/19/java-phpstorm-activedirectory-folder-redirection-%d0%b8-%d0%bf%d1%80%d0%be%d0%b1%d0%bb%d0%b5%d0%bc%d0%b0-%d0%b7%d0%b0%d0%bf%d1%83%d1%81%d0%ba%d0%b0/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://russianpenguin.ru/2011/12/19/java-phpstorm-activedirectory-folder-redirection-%d0%b8-%d0%bf%d1%80%d0%be%d0%b1%d0%bb%d0%b5%d0%bc%d0%b0-%d0%b7%d0%b0%d0%bf%d1%83%d1%81%d0%ba%d0%b0/</feedburner:origLink></entry><entry><title type="text">Windows 7 автоматически не уходит в спящий режим</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/LmAapfOMv9U/" /><category term="Операционные Системы" /><category term="trouble" /><category term="windows" /><author><name>Penguin</name></author><updated>2011-12-18T09:43:54-08:00</updated><id>http://russianpenguin.ru/?p=558</id><summary type="html">Как понять, почему ваша система не уходит в спящий режим автоматически?</summary><content type="html">&lt;p&gt;Недавно столкнулся с проблемой: windows 7 отказывалась автоматически уходить в спящий режим. Решение оказалось очень простым &lt;img src='http://russianpenguin.ru/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /&gt;&lt;br /&gt;
&lt;span id="more-558"&gt;&lt;/span&gt;&lt;br /&gt;
Сначала нужно протрассировать события системы при попытке уйти в спящий режим&lt;/p&gt;
&lt;pre style="brush:shell"&gt;powercfg -energy&lt;/pre&gt;
&lt;p&gt;Система сгенерирует отчет, в котором можно будет найти причину ошибки.&lt;br /&gt;
В моем случае виноват быо драйвер rdbss&lt;/p&gt;
&lt;pre&gt;System Availability Requests:System Required Request
The device or driver has made a request to prevent the system from automatically entering sleep.
Driver Name \FileSystem\rdbss&lt;/pre&gt;
&lt;p&gt;Теперь нужно понять, почему он блокирует уход системы в спячку. Для этого нужно посмотреть список блокировок&lt;/p&gt;
&lt;pre style="brush:shell"&gt;powercfg -requests&lt;/pre&gt;
&lt;p&gt;Хм&amp;#8230; Виновным оказался образ лиска, открытый в daemon tools с samba-ресурса&lt;/p&gt;
&lt;pre&gt;DISPLAY:
None.

SYSTEM:
[DRIVER] \FileSystem\rdbss
A file has been opened across the network. File name: [\samba\soft\win\disk.iso] Process ID: [2944]

AWAYMODE:
None.&lt;/pre&gt;
&lt;p&gt;Отмонтируем образ, проверяем систему.&lt;/p&gt;
&lt;pre style="brush:shell"&gt;DISPLAY:
None.

SYSTEM:
None.

AWAYMODE:
None.&lt;/pre&gt;
&lt;p&gt;Система спокойно уходит в спячку автоматически.&lt;br /&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/07/22/svn-init-d-%d1%81%d0%ba%d1%80%d0%b8%d0%bf%d1%82-%d0%b4%d0%bb%d1%8f-debian/" rel="bookmark" title="22.07.2011"&gt;svn: init.d скрипт для debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/12/19/java-phpstorm-activedirectory-folder-redirection-%d0%b8-%d0%bf%d1%80%d0%be%d0%b1%d0%bb%d0%b5%d0%bc%d0%b0-%d0%b7%d0%b0%d0%bf%d1%83%d1%81%d0%ba%d0%b0/" rel="bookmark" title="19.12.2011"&gt;Java, PhpStorm, ActiveDirectory, перенаправление папок и проблема запуска&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/09/24/kohana-%d0%b8-php-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-put-%d0%b7%d0%b0%d0%bf%d1%80%d0%be%d1%81%d0%b0%d0%bc%d0%b8/" rel="bookmark" title="24.09.2011"&gt;Kohana и PHP: работа с PUT-запросами&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/02/01/windows-7-taskhost-exe-gruzit-processor/" rel="bookmark" title="01.02.2010"&gt;Windows 7: taskhost.exe &amp;#171;грузит&amp;#187; процессор&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2009/08/18/windows-7-problemy-c-setyu/" rel="bookmark" title="18.08.2009"&gt;Windows 7: проблемы c сетью&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 11.583 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/LmAapfOMv9U" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2011/12/18/windows-7-%d0%bd%d0%b5-%d1%83%d1%85%d0%be%d0%b4%d0%b8%d1%82-%d0%b2-%d1%81%d0%bf%d1%8f%d1%89%d0%b8%d0%b9-%d1%80%d0%b5%d0%b6%d0%b8%d0%bc-%d0%b0%d0%b2%d1%82%d0%be%d0%bc%d0%b0%d1%82%d0%be%d0%bc/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">7</slash:comments><feedburner:origLink>http://russianpenguin.ru/2011/12/18/windows-7-%d0%bd%d0%b5-%d1%83%d1%85%d0%be%d0%b4%d0%b8%d1%82-%d0%b2-%d1%81%d0%bf%d1%8f%d1%89%d0%b8%d0%b9-%d1%80%d0%b5%d0%b6%d0%b8%d0%bc-%d0%b0%d0%b2%d1%82%d0%be%d0%bc%d0%b0%d1%82%d0%be%d0%bc/</feedburner:origLink></entry><entry><title type="text">htaccess: избирательное открытие доступа к url</title><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/russianpenguin/~3/d6yO5ZpcAGg/" /><category term="КОДОшаблоны" /><category term="apache" /><category term="htaccess" /><category term="htpasswd" /><author><name>Penguin</name></author><updated>2011-11-30T07:02:14-08:00</updated><id>http://russianpenguin.ru/?p=545</id><summary type="html">Как сделать так, чтобы при доступе к сайту запрашивалось имя и пароль? А потом разрешить запросы к определенному url без ввода пароля?</summary><content type="html">&lt;p&gt;&lt;a href="http://russianpenguin.ru/wp-content/uploads/2011/11/2011-11-30_18-57_htaccess.png"&gt;&lt;img src="http://russianpenguin.ru/wp-content/uploads/2011/11/2011-11-30_18-57_htaccess-e1322665240880-150x57.png" alt="" title="htaccess" width="150" height="57" class="alignleft size-thumbnail wp-image-549" /&gt;&lt;/a&gt;Часто ли вы сталкивались с ситуацией, когда надо разрешить доступ к сайту только по логину паролю а потом разрешить вызов по определенному урлу без ввода пароля? Что может быть проще?&lt;br /&gt;
&lt;span id="more-545"&gt;&lt;/span&gt;&lt;br /&gt;
Код .htaccess&lt;/p&gt;
&lt;pre class="brush:shell"&gt;AuthType Basic
AuthName "Private zone. Only for administrator!"
AuthUserFile  .htpasswd
require valid-user&lt;/pre&gt;
&lt;p&gt;И создаем .htpasswd с учетной записью пользователя admin.&lt;/p&gt;
&lt;pre class="brush:shell"&gt;htpasswd -cm admin&lt;/pre&gt;
&lt;p&gt;А теперь нам надо избирательно разрешить доступ по определенным адресам. Чтобы у пользователя не запрашивалось пароля.&lt;/p&gt;
&lt;pre class="brush:shell"&gt;# Если урл начинается со строки /some/path
# то выставляем переменную some_path
SetEnvIf Request_URI "/some/path*" some_path
# Дальше стандартный код защиты при помощи .htpasswd
AuthType Basic
AuthName "Private zone. Only for administrator!"
AuthUserFile  .htpasswd
require valid-user
# Запрещаем все, что не разрешено
Deny from all
# И если установлена переменная окружения some_path,
# То разрешаем вызов без запроса авторизации
Allow from env=some_path
Satisfy any&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Похожие записи:&lt;/strong&gt;
&lt;ul class="similar-posts"&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/07/30/pear-%d0%bf%d1%80%d0%b8%d0%bd%d1%83%d0%b4%d0%b8%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%b0%d1%8f-%d1%83%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%ba%d0%b0-%d0%bf%d0%b0%d0%ba%d0%b5%d1%82%d0%be%d0%b2-beta-%d0%b2/" rel="bookmark" title="30.07.2011"&gt;PEAR: принудительная установка пакетов beta-версии&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/11/24/jqgrid-api-dlya-vzaimodejstviya-s-servernoj-chastyu-soxranenie-dannyx/" rel="bookmark" title="24.11.2010"&gt;jqGrid: API для взаимодействия с серверной частью &amp;#8212; сохранение данных&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2011/09/24/kohana-%d0%b8-php-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-put-%d0%b7%d0%b0%d0%bf%d1%80%d0%be%d1%81%d0%b0%d0%bc%d0%b8/" rel="bookmark" title="24.09.2011"&gt;Kohana и PHP: работа с PUT-запросами&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2012/02/10/php-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b-iterator-%d0%b8-iteratoraggregate-%d0%bf%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%ba%d0%b0/" rel="bookmark" title="10.02.2012"&gt;PHP: интерфейсы Iterator и IteratorAggregate. Практика применения.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://russianpenguin.ru/2010/11/06/apache2-avtomaticheskoe-sozdanie-virtualnyh-hostov/" rel="bookmark" title="06.11.2010"&gt;Apache2: Автоматическое создание виртуальных хостов&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;!-- Similar Posts took 24.943 ms --&gt;&lt;/p&gt;
&lt;img src="http://feeds.feedburner.com/~r/russianpenguin/~4/d6yO5ZpcAGg" height="1" width="1"/&gt;</content><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://russianpenguin.ru/2011/11/30/htaccess-%d0%b8%d0%b7%d0%b1%d0%b8%d1%80%d0%b0%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d0%b5-%d0%be%d1%82%d0%ba%d1%80%d1%8b%d1%82%d0%b8%d0%b5-%d0%b4%d0%be%d1%81%d1%82%d1%83%d0%bf%d0%b0-%d0%ba-url/feed/</wfw:commentRss><slash:comments xmlns:slash="http://purl.org/rss/1.0/modules/slash/">0</slash:comments><feedburner:origLink>http://russianpenguin.ru/2011/11/30/htaccess-%d0%b8%d0%b7%d0%b1%d0%b8%d1%80%d0%b0%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d0%b5-%d0%be%d1%82%d0%ba%d1%80%d1%8b%d1%82%d0%b8%d0%b5-%d0%b4%d0%be%d1%81%d1%82%d1%83%d0%bf%d0%b0-%d0%ba-url/</feedburner:origLink></entry></feed>

