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

<channel>
	<title>Разработка &#187; php</title>
	<atom:link href="http://www.job-blog.bullgare.ru/category/programming/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.job-blog.bullgare.ru</link>
	<description>о программировании и работе</description>
	<lastBuildDate>Fri, 03 Feb 2012 09:42:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Удобная работа с датами в php</title>
		<link>http://www.job-blog.bullgare.ru/2012/01/%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%b0%d1%8f-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%b4%d0%b0%d1%82%d0%b0%d0%bc%d0%b8-%d0%b2-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2012/01/%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%b0%d1%8f-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%b4%d0%b0%d1%82%d0%b0%d0%bc%d0%b8-%d0%b2-php/#comments</comments>
		<pubDate>Wed, 18 Jan 2012 09:54:54 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[datetime]]></category>
		<category><![CDATA[ссылка]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=1372</guid>
		<description><![CDATA[Периодически возникают задачи типа вернуть дату &#171;первого числа прошлого месяца&#187;, или &#171;прошлого понедельника&#187;. Это можно решить как-то так: $dt = self::getCurrentMonthStartDt(); $dt->setTime( 0, 0, 0 ); $dt->setDate( $dt->format( 'Y' ), $dt->format( 'm' ) - 1, 1 ); return $dt; ... $dt = new DateTime(); $dt->modify( '-' . ( $dt->format( 'N' ) - 8 ) . [...]]]></description>
			<content:encoded><![CDATA[<p>Периодически возникают задачи типа вернуть дату &laquo;первого числа прошлого месяца&raquo;, или &laquo;прошлого понедельника&raquo;.<br />
Это можно решить как-то так:</p>
<pre class="code">
	$dt = self::getCurrentMonthStartDt();
	$dt->setTime( 0, 0, 0 );
	$dt->setDate( $dt->format( 'Y' ), $dt->format( 'm' ) - 1, 1 );
	return $dt;
...
	$dt = new DateTime();
	$dt->modify( '-' . ( $dt->format( 'N' ) - 8 ) . ' days' );
	$dt->setTime( 0, 0, 0 );
	return $dt;
</pre>
<p>А можно гораздо проще:</p>
<pre class="code">
	$dt = new DateTime( 'first day of last month' );
	$dt->setTime( 0, 0, 0 );
	return $dt;
...
	$dt = new DateTime( 'mon this week' );
	$dt->setTime( 0, 0, 0 );
	return $dt;
</pre>
<p>It&#8217;s a kinda magic, но работает.<br />
<a href="http://www.php.net/manual/ru/datetime.formats.relative.php">http://www.php.net/manual/ru/datetime.formats.relative.php</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2012/01/%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%b0%d1%8f-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%b4%d0%b0%d1%82%d0%b0%d0%bc%d0%b8-%d0%b2-php/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Проблема при работе с расширением memcached в php</title>
		<link>http://www.job-blog.bullgare.ru/2011/10/%d0%bf%d1%80%d0%be%d0%b1%d0%bb%d0%b5%d0%bc%d0%b0-%d0%bf%d1%80%d0%b8-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b5-%d1%81-%d1%80%d0%b0%d1%81%d1%88%d0%b8%d1%80%d0%b5%d0%bd%d0%b8%d0%b5%d0%bc-memcached-%d0%b2-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2011/10/%d0%bf%d1%80%d0%be%d0%b1%d0%bb%d0%b5%d0%bc%d0%b0-%d0%bf%d1%80%d0%b8-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b5-%d1%81-%d1%80%d0%b0%d1%81%d1%88%d0%b8%d1%80%d0%b5%d0%bd%d0%b8%d0%b5%d0%bc-memcached-%d0%b2-php/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 12:19:29 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[администрирование]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[memcached]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=1260</guid>
		<description><![CDATA[Работал раньше сайт с memcache. Решили перейти на memcached. И повалились ошибки SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY, причём сначала одна CLIENT ERROR, а уже потом куча SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY. Гугление ничего не дало, а проблема оказалась в следующем: первая ошибка возникала из-за некорректного ключа (пробел [...]]]></description>
			<content:encoded><![CDATA[<p>Работал раньше сайт с memcache.<br />
Решили перейти на memcached.<br />
И повалились ошибки <strong>SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY</strong>, причём сначала одна <strong>CLIENT ERROR</strong>, а уже потом куча <strong>SERVER HAS FAILED AND IS DISABLED UNTIL TIMED RETRY</strong>.<br />
Гугление ничего не дало, а проблема оказалась в следующем: первая ошибка возникала из-за некорректного ключа (пробел в названии ключа), после чего сервер расстраивался, и больше ничего делать не давал.<br />
Ключ был следующий: <strong>info__rating DESC__1</strong>, генерился автоматически и никаких проблем при использовании его в memcache не вызывал. Понятное дело, что ключ плохой, но это не мешало другому расширению успешно работать.<br />
А решение применили банальное: <strong>$Key = str_replace( &#8216; &#8216;, &#8216;_&#8217;, $Key );</strong>, теперь вроде работает).<br />
Окончательно все проблемы решила опция</p>
<pre class="code">
$this->setOption( Memcached::OPT_BINARY_PROTOCOL,   true );
</pre>
<p>После этого лог ошибок стал пустым.<br />
Коллега, который этим вопросом плотно занимается, считает, что это оттого, что по умолчанию протокол используется plain text (а именно, ascii), и UTF-символы интерпретируются неправильно (у нас ферма из нескольких машин, и на каждой окружение несколько отличается, к сожалению). И как только включили бинарный протокол, разногласия исчезли.</p>
<pre class="code">
	function __construct()
	{
		parent::__construct();

		$this->setOption( Memcached::OPT_BINARY_PROTOCOL, true );
		$this->setOption( Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT );
		$this->setOption( Memcached::OPT_HASH, Memcached::HASH_CRC );
		$this->setOption( Memcached::OPT_SERVER_FAILURE_LIMIT, 3 );
		$this->setOption( Memcached::OPT_NO_BLOCK, true );									// асинхронный ввод-вывод
		$this->setOption( Memcached::OPT_TCP_NODELAY, true );									// при работе с сокетами надо потестить - может ускорить работу

		$this->connection = $this->addServers( array(	array( &lt;хост&gt;, &lt;порт&gt; ) ) );
		...
	}
</pre>
<p>При использовании ключа:</p>
<pre class="code">
	...
	$key = str_replace( array( ' ', ',', ':' ), '_', $key );

	if ( strlen($key) > 220 ) {
		$key = md5( $key );
	}
	...
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2011/10/%d0%bf%d1%80%d0%be%d0%b1%d0%bb%d0%b5%d0%bc%d0%b0-%d0%bf%d1%80%d0%b8-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b5-%d1%81-%d1%80%d0%b0%d1%81%d1%88%d0%b8%d1%80%d0%b5%d0%bd%d0%b8%d0%b5%d0%bc-memcached-%d0%b2-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Борьба с утечками памяти в php</title>
		<link>http://www.job-blog.bullgare.ru/2011/09/%d0%b1%d0%be%d1%80%d1%8c%d0%b1%d0%b0-%d1%81-%d1%83%d1%82%d0%b5%d1%87%d0%ba%d0%b0%d0%bc%d0%b8-%d0%bf%d0%b0%d0%bc%d1%8f%d1%82%d0%b8-%d0%b2-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2011/09/%d0%b1%d0%be%d1%80%d1%8c%d0%b1%d0%b0-%d1%81-%d1%83%d1%82%d0%b5%d1%87%d0%ba%d0%b0%d0%bc%d0%b8-%d0%bf%d0%b0%d0%bc%d1%8f%d1%82%d0%b8-%d0%b2-php/#comments</comments>
		<pubDate>Fri, 23 Sep 2011 08:24:28 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[администрирование]]></category>
		<category><![CDATA[memory]]></category>
		<category><![CDATA[memory leaks]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=1234</guid>
		<description><![CDATA[$limit = 512; $thresholdDelta = 10; ini_set('memory_limit', $limit . 'm'); ... $memoryThresholdReached = false; $memoryThreshold = ( $limit - $thresholdDelta ) * 1024 * 1024; ... while ( $user = $db->plain_fetch( $result ) ) { ... // тут работа с данными ... // проверка на превышение опасного порога использования памяти if ( ! $memoryThresholdReached &#038;&#038; [...]]]></description>
			<content:encoded><![CDATA[<pre class="code">
	$limit = 512;
	$thresholdDelta = 10;
	ini_set('memory_limit', $limit . 'm');
	...
	$memoryThresholdReached = false;
	$memoryThreshold = ( $limit - $thresholdDelta ) * 1024 * 1024;
	...
	while ( $user = $db->plain_fetch( $result ) )
	{
		...
	// тут работа с данными
		...
	// проверка на превышение опасного порога использования памяти
		if ( ! $memoryThresholdReached &#038;&#038; memory_get_usage( true ) > $memoryThreshold )
		{
			$memoryThresholdReached = true;
			try {
				throw new SystemException( 'Превышен порог использования памяти...' );
			}
			catch ( Exception $e ) {}
		}
	}
</pre>
<p>Более серьёзные способы &#8211; просмотр стека (strace -f -p $pid) и дебаг php C-шным дебаггером DBG.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2011/09/%d0%b1%d0%be%d1%80%d1%8c%d0%b1%d0%b0-%d1%81-%d1%83%d1%82%d0%b5%d1%87%d0%ba%d0%b0%d0%bc%d0%b8-%d0%bf%d0%b0%d0%bc%d1%8f%d1%82%d0%b8-%d0%b2-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Как настроить Smarty для удобной работы (+наследование)</title>
		<link>http://www.job-blog.bullgare.ru/2011/07/%d0%ba%d0%b0%d0%ba-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b8%d1%82%d1%8c-smarty-%d0%b4%d0%bb%d1%8f-%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%be%d0%b9-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%8b-%d0%bd%d0%b0%d1%81/</link>
		<comments>http://www.job-blog.bullgare.ru/2011/07/%d0%ba%d0%b0%d0%ba-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b8%d1%82%d1%8c-smarty-%d0%b4%d0%bb%d1%8f-%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%be%d0%b9-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%8b-%d0%bd%d0%b0%d1%81/#comments</comments>
		<pubDate>Sat, 02 Jul 2011 20:33:29 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[smarty]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=1177</guid>
		<description><![CDATA[Smarty &#8211; странноватый и глючноватый шаблонизатор, если сравнивать с Django. Но под php ничего под руку не попалось, чтобы работало из коробки, было просто в настройке, и, к тому же, когда-то давно я его уже ковырял. В общем, нужно было срочно прикрутить шаблонизатор &#8211; сделал следующее. В классе, ответственном за вывод: private static function getSmarty( [...]]]></description>
			<content:encoded><![CDATA[<p>Smarty &#8211; странноватый и глючноватый шаблонизатор, если сравнивать с Django.<br />
Но под php ничего под руку не попалось, чтобы работало из коробки, было просто в настройке, и, к тому же, когда-то давно я его уже ковырял.<br />
В общем, нужно было срочно прикрутить шаблонизатор &#8211; сделал следующее.</p>
<ul>
<li>В классе, ответственном за вывод:
<pre class="code">	private static function getSmarty( array $Params )
	{
		require_once( SMARTY . 'Smarty.class.php' );
		$smarty = new Smarty();
		$smarty-&gt;error_reporting = E_ALL &amp; ~E_NOTICE;
		$smarty-&gt;force_compile = true;
		$smarty-&gt;left_delimiter = '{{';
		$smarty-&gt;right_delimiter = '}}';
		$smarty-&gt;template_dir = TEMPLATE;
		foreach ( $Params as $key =&gt; $value ) {
			$smarty-&gt;assign( $key, $value );
		}

		return $smarty;
	}

	public function renderToView( rController $Controller, $Debug = false )
	{
		$contentType = $Controller-&gt;getContentType();
		self::setHeaders( $contentType );
		switch ( $contentType )
		{
			case self::CONTENT_TYPE_JSON :
				echo json_encode( $Controller-&gt;getTemplateData() );
				break;
			case self::CONTENT_TYPE_HTML :
			default :
				$templatePath = $Controller-&gt;getTemplatePath();
				if ( ! $templatePath ) {
					$templatePath = $this-&gt;generateTemplatePath( $Controller );
				}
				if ( ! file_exists( TEMPLATE . $templatePath ) )
				{
					if ( $Debug ) {
						echo 'tried ' . TEMPLATE . $templatePath;
					}
					$templatePath = $this-&gt;defaultTemplatePath;
				}

				self::getSmarty( $Controller-&gt;getTemplateData() )-&gt;display( $templatePath );
		}
	}</pre>
</li>
<li> Во вьюхе:
<pre class="code">// layout.tpl
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
&lt;head&gt;
&lt;title&gt;{{if isset( $title )}}{{$title}}{{else}}{{$defaultTitle}}{{/if}}&lt;/title&gt;
&lt;script type="text/javascript" src="/js/main.js"&gt;&lt;/script&gt;
{{block name="head"}}{{/block}}
&lt;/head&gt;
&lt;body&gt;
{{block name="content"}}{{/block}}
&lt;/body&gt;

// index.tpl
{{extends 'layout.tpl'}}
{{block name="content"}}
	{{assign 'myparamm' 'Bob'}}
	myparamm {{$myparamm}}
{{/block}}</pre>
</li>
</ul>
<p>Примечательно то, что если (см. код <strong>index.tpl</strong>) присвоение значения переменной <strong>myparamm</strong> вынести за пределы конструкции <strong>block</strong>, то переменная внутри будет неопределена, в документации об этом ни слова)). Также для конструкции <strong>block</strong> можно указать параметры prepend или append, чтобы не перетирать родительский блок, а дописывать в конец или в начало блока.<br />
В общем получаются похожие на django шаблоны, и жить немного легче.</p>
<p>Насчёт наследования в Smarty 3 можно почитать на официальном сайте:</p>
<ul>
<li><a href="http://www.smarty.net/docs/en/advanced.features.template.inheritance.tpl">http://www.smarty.net/docs/en/advanced.features.template.inheritance.tpl</a></li>
<li><a href="http://www.smarty.net/docs/en/language.function.extends.tpl">http://www.smarty.net/docs/en/language.function.extends.tpl</a></li>
<li><a href="http://www.smarty.net/docs/en/language.function.block.tpl">http://www.smarty.net/docs/en/language.function.block.tpl</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2011/07/%d0%ba%d0%b0%d0%ba-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b8%d1%82%d1%8c-smarty-%d0%b4%d0%bb%d1%8f-%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%be%d0%b9-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d1%8b-%d0%bd%d0%b0%d1%81/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Организация очередей на PHP</title>
		<link>http://www.job-blog.bullgare.ru/2011/06/%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d0%be%d1%87%d0%b5%d1%80%d0%b5%d0%b4%d0%b5%d0%b9-%d0%bd%d0%b0-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2011/06/%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d0%be%d1%87%d0%b5%d1%80%d0%b5%d0%b4%d0%b5%d0%b9-%d0%bd%d0%b0-php/#comments</comments>
		<pubDate>Wed, 08 Jun 2011 10:37:53 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Pheanstalk]]></category>
		<category><![CDATA[queue]]></category>
		<category><![CDATA[очереди]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=1124</guid>
		<description><![CDATA[Решили использовать Pheanstalk, который представляет собой PHP-клиента для Beanstalk. Простой, чётко работает, всё построено на иерархии исключений, т.е. легко применять. Всё сводится к следующему: $this->queueManager = new Pheanstalk( '127.0.0.1' ); $this->queueManager->useTube('my_jobs_1')->put( $JobData ); $this->job = $this->queueManager->watch('my_jobs_1')->ignore('default')->reserve( 0 ); // 0 - чтобы не ждать, когда появятся новые джобы (чтобы запускать php-скрипт кроном, а не требовать [...]]]></description>
			<content:encoded><![CDATA[<p>Решили использовать <a href="https://github.com/pda/pheanstalk/commits/master/doc">Pheanstal</a>k, который представляет собой PHP-клиента для <a href="https://github.com/kr/beanstalkd/wiki/faq">Beanstalk</a>.<br />
Простой, чётко работает, всё построено на иерархии исключений, т.е. легко применять.<br />
Всё сводится к следующему: </p>
<pre class="code">
$this->queueManager = new Pheanstalk( '127.0.0.1' );
$this->queueManager->useTube('my_jobs_1')->put( $JobData );
$this->job = $this->queueManager->watch('my_jobs_1')->ignore('default')->reserve( 0 ); // 0 - чтобы не ждать, когда появятся новые джобы (чтобы запускать php-скрипт кроном, а не требовать висения в памяти демоном)
$this->queueManager->delete( $this->job );
</pre>
<p>Для работы должен быть запущен демон Beanstalk:</p>
<pre class="code">
$ beanstalkd -d
</pre>
<p><a href="http://nubyonrails.com/articles/about-this-blog-beanstalk-messaging-queue">Ещё почитать</a>.<br />
<a href="http://www.contentwithstyle.co.uk/content/php-worker-processes-with-beanstalk-and-daemontools">Интересный пример использования Pheanstalk</a>, <a href="http://pastebin.com/uRNZXQ35">менее интересный пример</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2011/06/%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f-%d0%be%d1%87%d0%b5%d1%80%d0%b5%d0%b4%d0%b5%d0%b9-%d0%bd%d0%b0-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Новое в PHP 5.4 &#8211; трейты (traits)</title>
		<link>http://www.job-blog.bullgare.ru/2011/03/%d0%bd%d0%be%d0%b2%d0%be%d0%b5-%d0%b2-php-5-4-%d1%82%d1%80%d0%b5%d0%b9%d1%82%d1%8b-traits/</link>
		<comments>http://www.job-blog.bullgare.ru/2011/03/%d0%bd%d0%be%d0%b2%d0%be%d0%b5-%d0%b2-php-5-4-%d1%82%d1%80%d0%b5%d0%b9%d1%82%d1%8b-traits/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 20:04:50 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[php 5.4]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=995</guid>
		<description><![CDATA[Вкратце: трейт (аналог mixin в Ruby) &#8211; возможность в классе использовать функционал нескольких классов в обход традиционного наследования (по-моему, костыль, чтобы не реализовывать множественное наследование). Всё сводится к новой инструкции use внутри класса, при этом класс, функциональность которого нужно подмешивать. объявляется инструкцией trait. trait Singleton { public static function getInstance() { ... } } class [...]]]></description>
			<content:encoded><![CDATA[<p>Вкратце: трейт (аналог mixin в Ruby) &#8211; возможность в классе использовать функционал нескольких классов в обход традиционного наследования (по-моему, костыль, чтобы не реализовывать множественное наследование).<br />
Всё сводится к новой инструкции <strong>use</strong> внутри класса, при этом класс, функциональность которого нужно подмешивать. объявляется инструкцией <strong>trait</strong>.</p>
<pre class="code">
trait Singleton {
    public static function getInstance() { ... }
}

class A {
    use Singleton;
    // ...
}

class B extends ArrayObject {
    use Singleton;
    // ...
}

// Singleton method is now available for both classes
A::getInstance();
B::getInstance();
</pre>
<p>Подробнее:<br />
<a href="http://simas.posterous.com/new-to-php-54-traits">New to PHP 5.4: Traits</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2011/03/%d0%bd%d0%be%d0%b2%d0%be%d0%b5-%d0%b2-php-5-4-%d1%82%d1%80%d0%b5%d0%b9%d1%82%d1%8b-traits/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Паттерны проектирования на PHP</title>
		<link>http://www.job-blog.bullgare.ru/2011/03/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd%d1%8b-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d0%bd%d0%b0-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2011/03/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd%d1%8b-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d0%bd%d0%b0-php/#comments</comments>
		<pubDate>Sun, 27 Mar 2011 19:40:48 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[паттерн]]></category>
		<category><![CDATA[паттерны проектирования]]></category>
		<category><![CDATA[Ссылки]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=992</guid>
		<description><![CDATA[http://css.dzone.com/books/practical-php-patterns]]></description>
			<content:encoded><![CDATA[<p><a href="http://css.dzone.com/books/practical-php-patterns">http://css.dzone.com/books/practical-php-patterns</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2011/03/%d0%bf%d0%b0%d1%82%d1%82%d0%b5%d1%80%d0%bd%d1%8b-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d0%bd%d0%b0-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Использование Twitter-API в PHP</title>
		<link>http://www.job-blog.bullgare.ru/2011/03/%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-twitter-api-%d0%b2-php/</link>
		<comments>http://www.job-blog.bullgare.ru/2011/03/%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-twitter-api-%d0%b2-php/#comments</comments>
		<pubDate>Thu, 03 Mar 2011 13:52:45 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Twitter]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=956</guid>
		<description><![CDATA[Есть такая библиотека &#8211; twitter-async (лицензия &#8211; свободное распространение и использование). Из неё нужно включить в проект файлы EpiCurl EpiOAuth EpiSequence EpiTwitter Далее на twitter.com нужно завести приложение. После успешной регистрации Twitter выдаст полезные данные для oAuth-авторизации, нужны из них два: Consumer key и Consumer secret &#8211; это авторизационные данные приложения, их нужно сохранить где-нибудь, [...]]]></description>
			<content:encoded><![CDATA[<p>Есть такая библиотека &#8211; <a href="https://github.com/jmathai/twitter-async">twitter-async</a> (лицензия &#8211; свободное распространение и использование).<br />
Из неё нужно включить в проект файлы </p>
<ul>
<li><strong>EpiCurl</strong></li>
<li><strong>EpiOAuth</strong></li>
<li><strong>EpiSequence</strong></li>
<li><strong>EpiTwitter</strong></li>
</ul>
<p>Далее на twitter.com нужно <a href="https://dev.twitter.com/apps/new">завести приложение</a>.<br />
После успешной регистрации Twitter выдаст полезные данные для oAuth-авторизации, нужны из них два: <strong>Consumer key</strong> и <strong>Consumer secret</strong> &#8211; это авторизационные данные приложения, их нужно сохранить где-нибудь, к примеру, в базе.<br />
<span id="more-956"></span><br />
Для работы с твиттером создаём обёртку:</p>
<pre class="code">
class Twitter {
	public static function connect()
	{
		$twitter = self::$twitter;
		if (! $twitter)
		{
			$twitter = new EpiTwitter(
				self::get('consumer_key'),
				self::get('consumer_secret'),
				self::get('oauth_token'),
				self::get('oauth_token_secret')
			);
		}
		return $twitter;
	}
}
</pre>
<p>После этого нужно создать страничку, чтобы пользователь смог разрешить использовать свой аккаунт на твиттере созданному нами приложению.</p>
<pre class="code">
&lt;?
$error = array();
try
{
	// разрешил ли пользователь использовать твиттер
	if ( Twitter::get('oauth_token') )
	{
		$twitterInfo = $twitterObj->get_accountVerify_credentials();
		$twitterInfo->response;
	}
	else {
		$authorizationUrl = $twitterObj->getAuthorizeUrl();
	}
}
catch ( EpiOAuthException $e ) {
	$errors[] = Twitter::getExceptionError( $e );
}
catch ( EpiTwitterException $e ) {
	$errors[] = Twitter::getExceptionError( $e );
}
?&gt;
&lt;? if ( $twitterInfo ) : ?&gt;
	&lt;dl class="twitter-info"&gt;
		&lt;dt&gt;
			&lt;a href="http://twitter.com/&lt;?= $twitterInfo-&gt;screen_name ?&gt;" style="background: url( '&lt;?= $twitterInfo-&gt;profile_image_url ?&gt;' ) no-repeat left center"&gt;
				&lt;?= $twitterInfo-&gt;name ?&gt;
			&lt;/a&gt;
		&lt;/dt&gt;
		&lt;dd&gt;
			&lt;?= 'Twitter protocol is enabled' ?&gt;, &lt;a href="/disable"&gt;&lt;?= 'disable' ?&gt;&lt;/a&gt;.
		&lt;/dd&gt;
	&lt;/dl&gt;
&lt;? else : ?&gt;
	&lt;dl class="twitter-info"&gt;
		&lt;dt&gt;&lt;/dt&gt;
		&lt;dd&gt;
			&lt;?= 'Twitter protocol is disabled' ?&gt;, &lt;a href="&lt;?= $authorizationUrl ?&gt;"&gt;&lt;?= 'enable' ?&gt;&lt;/a&gt;.
		&lt;/dd&gt;
	&lt;/dl&gt;
&lt;? endif ?&gt;
</pre>
<p>в метод <strong>getAuthorizeUrl(NULL, array(&#8216;oauth_callback&#8217; => &#8216;http://mysite.my/&#8217; . $dynamicUrl))</strong> можно передавать параметром url, на который нужно редиректить пользователя.</p>
<p>Страничка, на которую редиректится пользователь c twitter.com:</p>
<pre class="code">
	$twitterObj = Twitter::connect();
	$twitterObj->setToken( $GET['oauth_token'] );
	$token = $twitterObj->getAccessToken();
// сохранение в базу параметров токена пользователя
	set( 'oauth_token', $token->oauth_token );
	set( 'oauth_token_secret', $token->oauth_token_secret );
// тут редирект на карточку
</pre>
<p>Страничка для сброса твиттера:</p>
<pre class="code">
// сброс параметров токена пользователя
	set( 'oauth_token', NULL );
	set( 'oauth_token_secret', NULL );
// тут редирект на карточку
</pre>
<p>Рассылка личных сообщений в Twitter:</p>
<pre class="code">
public static function send( $To, $Text )
{
	$res = array('status' => false, 'message' => translate( 'Twitter is not configured' ));
	try
	{
		$twitter = Twitter::connect();

		$sendStatus = $twitter->post_direct_messagesNew( array(
			'user' => $To,
			'text' => shortenText( SdfHelper::htmlToPlain( $Text ), 140 )
		) );

	// обращение к свойству response отправляет запрос
		$response = $sendStatus->response;
		$res['message'] = isset( $response['created_at'] ) ? $response['created_at'] : '';
		$res['status'] = true;
	}
	catch ( EpiOAuthException $e ) {
		$res['message'] = Twitter::getExceptionError( $e );
	}
	catch ( EpiTwitterException $e ) {
		$res['message'] = Twitter::getExceptionError( $e );
	}
	return $res;
}
</pre>
<p><strong>post_direct_messagesNew()</strong> преобразуется в POST-запрос к урлу <strong>direct_messages/new</strong>.</p>
<p>Кстати, вот <a href="http://www.1stwebdesigner.com/tutorials/twitter-app-oauth-php/">толковая статья об использовнии Twitter на английском</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2011/03/%d0%b8%d1%81%d0%bf%d0%be%d0%bb%d1%8c%d0%b7%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-twitter-api-%d0%b2-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Как правильно установить xdebug для удобной работы</title>
		<link>http://www.job-blog.bullgare.ru/2010/08/%d0%ba%d0%b0%d0%ba-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d1%8c%d0%bd%d0%be-%d1%83%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%b8%d1%82%d1%8c-xdebug-%d0%b4%d0%bb%d1%8f-%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%be/</link>
		<comments>http://www.job-blog.bullgare.ru/2010/08/%d0%ba%d0%b0%d0%ba-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d1%8c%d0%bd%d0%be-%d1%83%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%b8%d1%82%d1%8c-xdebug-%d0%b4%d0%bb%d1%8f-%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%be/#comments</comments>
		<pubDate>Tue, 17 Aug 2010 12:53:06 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[администрирование]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[xdebug]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=759</guid>
		<description><![CDATA[1. Скачиваем расширение &#8211; http://www.xdebug.org/download.php (я качаю ts) и копируем в папку с расширениями php. 2. В php.ini пишем zend_extension_ts = "/php_xdebug.dll" xdebug.remote_enable=1 xdebug.remote_handler=dbgp xdebug.remote_mode=req xdebug.remote_port=9000 xdebug.remote_host=localhost xdebug.idekey=bullgare ;ну или другой ;это для профилирования xdebug.profiler_enable=Off xdebug.profiler_output_dir="c:\traces" xdebug.profiler_enable_trigger=On xdebug.profiler_output_name = cachegrind.out.%t.%p После перезапуска апача phpinfo будет содержать раздел xdebug. 3. Качаем плагин для firefox &#8211; Xdebug [...]]]></description>
			<content:encoded><![CDATA[<p>1. Скачиваем расширение &#8211; <a href="http://www.xdebug.org/download.php">http://www.xdebug.org/download.php</a> (я качаю ts) и копируем в папку с расширениями php.<br />
2. В <strong>php.ini</strong> пишем</p>
<pre class="code">
zend_extension_ts = "<путь-к-папке-ext>/php_xdebug.dll"
xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_mode=req
xdebug.remote_port=9000
xdebug.remote_host=localhost
xdebug.idekey=bullgare ;ну или другой

;это для профилирования
xdebug.profiler_enable=Off
xdebug.profiler_output_dir="c:\traces"
xdebug.profiler_enable_trigger=On
xdebug.profiler_output_name = cachegrind.out.%t.%p
</pre>
<p>После перезапуска апача phpinfo будет содержать  раздел <strong>xdebug</strong>.<br />
<span id="more-759"></span><br />
3. Качаем плагин для firefox &#8211; <a href="http://www.softpedia.com/progDownload/Xdebug-Helper-Download-79882.html/">Xdebug Helper с неофициального сайта &#8211; http://www.softpedia.com/progDownload/Xdebug-Helper-Download-79882.html</a>, к сожалению, на официальном сайте его уже нет, там он называется EasyXdebug и не работает (<a href="https://addons.mozilla.org/nl/firefox/addon/58688">https://addons.mozilla.org/nl/firefox/addon/58688</a>).<br />
Он для нового firefox не подходит &#8211; надо поправить версию. Залазим в скачанный архив (можно временно переименовать в zip, к примеру), редактируем файл <strong>install.rdf</strong> &#8211; ставим параметр <strong>maxVersion=&raquo;5.0&#8243;</strong>. Сохраняем в архив, переименовываем его обратно (меняем расширение). Потом он ставится без проблем. Прописываем в настройках плагина тот же ключ, что и в <strong>php.ini</strong>.<br />
4. После этого в среде разработки настраиваем всё в соответствии с настройками php и плагина. Я лично пользуюсь phpStorm, в нём надо ткнуть в кнопку <strong>Select Debug configuration</strong>, создать новую конфигурацию, создать в конфигурации новый<strong>Server</strong>, у которого в <strong>Web server root URL</strong> пишем url к корню сервера, к примеру, http://example.com. Во вкладке <strong>Mappings</strong> в поле <strong>Local path</strong> пишем локальный путь к серверу (с:\mysite).<br />
В настройках конфигурации прописать браузер &#8211; firefox и idekey.<br />
5. Использование:<br />
В браузере ткнуть в правом нижнем углу кнопку <strong>Start/stop xdebug session</strong>, в IDE нажать на кнопку <strong>debug</strong>, поставить точку останова, обновить страничку.<br />
С момента на писания статьи IDE немного поменялась, про настройку лучше почитать в их официальном блоге &#8211; <a href="http://blogs.jetbrains.com/webide/2011/03/configure-php-debugging-in-phpstorm-2-0/">Configuring PHP debugging in PhpStorm 2.0</a>.</p>
<p>Если идёт работа через nginx+php-fpm, то надо прописать порт <strong>9900</strong>, к примеру (обычно fastcgi висит на 9000 порту). В <strong>nginx.conf</strong> в раздел <strong>http</strong> добавляем  <strong>fastcgi_read_timeout 600;</strong>, а в <strong>php/fpm/pool.d/www.conf</strong> &#8211; <strong>request_terminate_timeout = 600</strong> (это для Ubuntu;-) ). Нужно это для того, чтобы nginx и fastcgi не рвали соединение через 60 секунд. (<a href="http://habrahabr.ru/qa/1452/">http://habrahabr.ru/qa/1452/</a>).<br />
Xdebug helper уже почему-то не поддерживается, но его можно <a href="http://releases.mozilla.org/pub/mozilla.org/addons/3960/xdebug_helper-0.3.1-fx.xpi">скачать с официального сайта</a> (правда надо подправить install.rdf, т.к. он устарел), уже модифицированная версия &#8211; <a href='http://www.job-blog.bullgare.ru/wp-content/uploads/2010/08/xdebug_helper-0.3.1-fx.zip'>xdebug_helper-0.3.1-fx</a> (надо поставить расширение xpi). </p>
<p>Если на сервере идёт одновременная работа с нескольких разработческих машин, то надо в ini дописать</p>
<pre class="code">
xdebug.remote_connect_back = 1
;xdebug.remote_host закомментировать
</pre>
<p>Хотя это даст возможность любому зашедшему с правильным ключом запустить любой запрос в режиме отладки, что не хорошо для открытых извне серверов. Если же сервер открыт всем , то можно попробовать использовать<a href="http://derickrethans.nl/debugging-with-multiple-users.html"> Xdebug proxy</a> (phpStorm 2.1 поддерживает прокси).</p>
<p><a href="http://xdebug.org/docs/all_settings">Описание всех параметров xdebug</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2010/08/%d0%ba%d0%b0%d0%ba-%d0%bf%d1%80%d0%b0%d0%b2%d0%b8%d0%bb%d1%8c%d0%bd%d0%be-%d1%83%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%b8%d1%82%d1%8c-xdebug-%d0%b4%d0%bb%d1%8f-%d1%83%d0%b4%d0%be%d0%b1%d0%bd%d0%be/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Трассировка PHP-приложений с помощью xdebug</title>
		<link>http://www.job-blog.bullgare.ru/2010/07/%d1%82%d1%80%d0%b0%d1%81%d1%81%d0%b8%d1%80%d0%be%d0%b2%d0%ba%d0%b0-php-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b9-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-xdebug/</link>
		<comments>http://www.job-blog.bullgare.ru/2010/07/%d1%82%d1%80%d0%b0%d1%81%d1%81%d0%b8%d1%80%d0%be%d0%b2%d0%ba%d0%b0-php-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b9-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-xdebug/#comments</comments>
		<pubDate>Fri, 30 Jul 2010 10:37:46 +0000</pubDate>
		<dc:creator>bullgare</dc:creator>
				<category><![CDATA[php]]></category>
		<category><![CDATA[xdebug]]></category>
		<category><![CDATA[отладка]]></category>

		<guid isPermaLink="false">http://www.job-blog.bullgare.ru/?p=748</guid>
		<description><![CDATA[Вот достаточно подробная статья на эту тему. В принципе достаточно написать xdebug_start_trace('&#60;Путь-к файлу&#62;.html', XDEBUG_TRACE_HTML); ... ... xdebug_stop_trace();]]></description>
			<content:encoded><![CDATA[<p>Вот достаточно подробная <a href="http://habrahabr.ru/blogs/php/31463/">статья</a> на эту тему.<br />
В принципе достаточно написать</p>
<pre class="code">
xdebug_start_trace('&lt;Путь-к файлу&gt;.html', XDEBUG_TRACE_HTML);
...
...
xdebug_stop_trace();
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.job-blog.bullgare.ru/2010/07/%d1%82%d1%80%d0%b0%d1%81%d1%81%d0%b8%d1%80%d0%be%d0%b2%d0%ba%d0%b0-php-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b9-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-xdebug/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

