<?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>CTAPbIu_MABP&#039;s BLOG &#187; PHP</title>
	<atom:link href="http://mabp.kiev.ua/category/programming/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://mabp.kiev.ua</link>
	<description>Не вижу проблем, кроме лени! &#169; Старый Мавр</description>
	<lastBuildDate>Fri, 10 Sep 2010 00:35:02 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Быстрый и грязный хак вордпресса</title>
		<link>http://mabp.kiev.ua/2009/12/18/quick-and-dirty-wordpress-hack/</link>
		<comments>http://mabp.kiev.ua/2009/12/18/quick-and-dirty-wordpress-hack/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 16:15:24 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1167</guid>
		<description><![CDATA[Продолжая тему блогов которых я читаю, не могу сказать что все даже очень популярные авторы заботятся об удобстве чтения своих статей. Наглядный пример это блоги на вордпрессе. 


По умолчанию вордпресс заменяет [простите за английский, но так наверное будет лучше] double quotation marks (") на double angels («») не очень вникая в очередность, поэтому можно встретить [...]]]></description>
			<content:encoded><![CDATA[<p>Продолжая <a href="http://mabp.kiev.ua/2009/12/08/fucking-siteowners/">тему</a> блогов которых я читаю, не могу сказать что все даже очень популярные авторы заботятся об удобстве чтения своих статей. Наглядный пример это блоги на вордпрессе. </p>
<span id="more-1167">
</span>
<p>По умолчанию вордпресс заменяет [простите за английский, но так наверное будет лучше] double quotation marks (") на double angels («») не очень вникая в очередность, поэтому можно встретить »слово» в »кавычках«. Так же заменяются quotation marks (') на apostrophe (’), three dots (...) на ellipses (…), two or three hyphens (---) на dash (—) и тд. Конечно есть парачка поправок, типа того что если в кирилических доменах xn-- заменилось на xn— то оно заменится обратно, но это не спасает.</p>
<p>В результате всех этих замен становиться совершенно невозможно постить код потому что вместо</p>
<pre>
<code class="javascript">

"This' 'cause of you...".test(/[0-9--]/);

</code>
</pre>
<p>Получается</p>
<pre>
<code class="javascript">

«This’ ’cause of you…«.test(/[0-9—]/);

</code>
</pre>
<p>Регулярка, кстати, правильная.</p>
<p>Но нашим доблестным сайтоводам ванна по колено и холодильник по плечё, нет чтоб сделать удобно, они постят как есть. При этом если скопировать то что получается в результате то оно никогда работать не будет.</p>
<p>Но это в лучшем случаи в худшем если запостить статью содержащую javascript и сделать там логический отступ в два перевода каретки то этот двойной отступ заменится на &lt;p&gt;&lt;/p&gt; после чего скрипт перестанет работать.</p>
<p>Не помню но кажетсья было еще пару подобных прелестей, но результат один - геморой при разборе примера кода.</p>
<p>Вобщем я это все пишу для того чтобы показать вам дорогие мои сайтоводы как это побороть. Открываем файл \wordpress\wp-includes\formatting.php и в первой же функции (если у вас wp 2.8.6) под названием wptexturize ищем кусок</p>
<pre>
<code class="php">

for ( $i = 0; $i < $stop; $i++ )

</code>
</pre>
<p>Ровно перед ним надо влепить вот таую конструкцию</p>
<pre>
<code class="php">

$cockney = $cockneyreplace = $static_characters = $static_replacements = $dynamic_characters = $dynamic_replacements = array();

</code>
</pre>
<p>Есть правда подозрения что вообще всю функцию надо закоментарить, но тогда что-то ломается, не помню что, давно проверял. Дальше больше, надо найти функцию wpautop и заменить ее полностью на:</p>
<pre>
<code class="php">

function wpautop($pee, $br = 1) {
	if ($br) {
		$pee = preg_replace_callback('/&lt;(script|style|code|pre).*?&lt;\/\\1&gt;/s', create_function('$matches', 'return str_replace("\n", "&lt;WPPreserveNewline /&gt;", $matches[0]);'), $pee);
		$pee = preg_replace('|&gt;\s*&lt;|', '&gt;&lt;', $pee);
		$pee = preg_replace('|(?&lt;!&lt;br /&gt;)\s*\n|', "&lt;br /&gt;\n", $pee); // optionally make line breaks
		$pee = str_replace("&gt;&lt;", "&gt;\n&lt;", $pee);
		$pee = str_replace('&lt;WPPreserveNewline /&gt;', "\n", $pee);
	}
	return $pee;
}

</code>
</pre>
<p>Все. После этого можно поcтить любой код и любые символы (посмотрите код этой статьи тут все символы "настоящие", а не мнемоники &amp;nbsp;). Будут траблы пишите в каменты.</p>
<br />
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/12/18/quick-and-dirty-wordpress-hack/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Non-triming space</title>
		<link>http://mabp.kiev.ua/2009/12/01/non-triming-space/</link>
		<comments>http://mabp.kiev.ua/2009/12/01/non-triming-space/#comments</comments>
		<pubDate>Tue, 01 Dec 2009 17:16:30 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[regex]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1143</guid>
		<description><![CDATA[Когда Женя показал мне свою заметку о неубиваймом пробеле я подумал это недостатки php и сказал, что в Java такой фигни нет и не будет. Оказалось показалось, Java тоже грешит этой фигней.





package ua.kiev.mabp;


/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 01.12.2009
 * Time: 18:48:00
 */
public class TrimDemo {
    public [...]]]></description>
			<content:encoded><![CDATA[<p>Когда Женя показал мне свою <a href="http://vedeney.org.ua/php/trim-function-doesnt-clean-out-ascii-code-160/" rel="nofollow external">заметку</a> о неубиваймом пробеле я подумал это недостатки php и сказал, что в <a href="http://mabp.kiev.ua/category/programming/java/">Java</a> такой фигни нет и не будет. Оказалось показалось, <a href="http://mabp.kiev.ua/category/programming/java/">Java</a> тоже грешит этой фигней.</p>
<span id="more-1143">
</span>
<pre>
<code class="java">

package ua.kiev.mabp;


/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 01.12.2009
 * Time: 18:48:00
 */
public class TrimDemo {
    public static void main(String[] args) {
        System.out.print("".concat(String.valueOf(new char[]{160, 160, 160})).trim().length());
    }
}

</code>
</pre>
<p>И еще <a href="http://www.jstoolbox.com/2009/11/01/funkciya-trim/" rel="nofollow external">лик</a> в тему</p>
<br />
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/12/01/non-triming-space/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pattern: Decorator</title>
		<link>http://mabp.kiev.ua/2009/08/03/pattern-decorator/</link>
		<comments>http://mabp.kiev.ua/2009/08/03/pattern-decorator/#comments</comments>
		<pubDate>Mon, 03 Aug 2009 21:35:36 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=1097</guid>
		<description><![CDATA[Сколько раз обещаю себе больше не писать на PHP, и всеравно пишу. Вот и недавно разродился небольшим классом реализующим шаблон декоратор.





class Decorator {
	protected $obj;
	public function __construct($name,$args=null){
		if (is_object($name)) {
			$this->obj = $name;
		} else if($args) {
			$reflection = new ReflectionClass($name);
			$this->obj = $reflection->newInstanceArgs($args);
		} else {
			$this->obj = new $name;
		}
	}


	public function __call($name,$args){
		if($args)
			return call_user_func_array(array($this->obj,$name), $args);
		else
			return $this->obj->{$name}();
	}
}



Все началось как пример одному долбаёбу на форуме, [...]]]></description>
			<content:encoded><![CDATA[<p>Сколько раз обещаю себе больше не писать на <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a>, и всеравно пишу. Вот и недавно разродился небольшим классом реализующим шаблон декоратор.</p>
<span id="more-1097">
</span>
<pre>
<code class="php">

class Decorator {
	protected $obj;
	public function __construct($name,$args=null){
		if (is_object($name)) {
			$this->obj = $name;
		} else if($args) {
			$reflection = new ReflectionClass($name);
			$this->obj = $reflection->newInstanceArgs($args);
		} else {
			$this->obj = new $name;
		}
	}


	public function __call($name,$args){
		if($args)
			return call_user_func_array(array($this->obj,$name), $args);
		else
			return $this->obj->{$name}();
	}
}

</code>
</pre>
<p>Все началось как пример <a href="http://pyha.ru/forum/topic/3067.msg61203#msg61203" rel="nofollow external">одному долбаёбу на форуме</a>, а закончилось как небольшой но прикольный класс. Естественно сначала я пару раз переписал пример, потом потестил его на локальном сервере и только потом написал эту статью, так что в классе есть небольшие изменения.</p>
<p>На вопрос нах вообще нуже декоратор я отвечать не буду - читайте вики или еще что-то. А вот на вопрос как это работает отвечу. Для начала создадим класс который нужно декорировать.</p>
<pre>
<code class="php">

class MyClass {
	private $property;
	public function __construct($property){
		$this->property = $property;
	}
	public function printMethodName(){
		echo __METHOD__;
	}


	public function printMyArgument($arg){
		echo $arg;
	}


	public function printMyProperty(){
		echo $this->property;
	}
	public function myDecoratedMethod(){
		echo "Decorated Method!";
	}
}

</code>
</pre>
<p>Как понятно методы особой смысловой нагрузки не несут, а только показывают что были вызваны именно они. Теперь создадим класс производный от декоратора, который будет декорировать последний метод класса MyClass.</p>
<pre>
<code class="php">

class ConcreteDecorator extends Decorator {
	public function myDecoratingMethod(){
		return $this->myDecoratedMethod();
	}
}

</code>
</pre>
<p>Теперь это все можно использовать примерно вот таким образом:</p>
<pre>
<code class="php">

$myObj = new ConcreteDecorator("MyClass", array("String passed via constructor"));


$myObj->printMyProperty();
$myObj->printMethodName();
$myObj->printMyArgument("String passed via printMyArgument");
$myObj->myDecoratingMethod();

</code>
</pre>
<p>Но что-то как-то некрасиво получается, надо бы добавить в после каждого метода обрыв строки, для этого создадим еще один декоратор:</p>
<pre>
<code class="php">

class MyNewLineDecorator extends Decorator {
	public function __call($name,$args){
		parent::__call($name,$args);
		echo "&lt;br /&gt;";
	}
}

</code>
</pre>
<p>И добавим его в код.</p>
<pre>
<code class="php">

$myObj = new ConcreteDecorator("MyClass", array("String passed via constructor"));
$myObj = new MyNewLineDecorator($myObj);


$myObj->printMyProperty();
$myObj->printMethodName();
$myObj->printMyArgument("String passed via printMyArgument");
$myObj->myDecoratingMethod();

</code>
</pre>
<p>В результате получаем:</p>
<pre>

String passed via constructor&lt;br /&gt;
MyClass::printMethodName&lt;br /&gt;
String passed via printMyArgument&lt;br /&gt;
Decorated Method!&lt;br /&gt;

</pre>
<p>Приятного использования.</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/08/03/pattern-decorator/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Pattern: Singleton</title>
		<link>http://mabp.kiev.ua/2009/04/04/pattern-singleton/</link>
		<comments>http://mabp.kiev.ua/2009/04/04/pattern-singleton/#comments</comments>
		<pubDate>Fri, 03 Apr 2009 23:01:26 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=999</guid>
		<description><![CDATA[Шаблон проектирования Singleton (одиночка) используется для того чтобы класс можно было создать только один раз. На практике он применяется вместе с другим шаблонами проектирования такими как pattern Registry и pattern ServiceLocator






class Singleton {
	private static $instance; // object


	/**
	 * Private constructor does nothing
	 *
	 */
	final private function __construct(){
		/* ... */
	}


	/**
	 * Return the single instance of [...]]]></description>
			<content:encoded><![CDATA[<p>Шаблон проектирования Singleton (одиночка) используется для того чтобы класс можно было создать только один раз. На практике он применяется вместе с другим шаблонами проектирования такими как <a href="http://mabp.kiev.ua/2008/04/17/pattern_registry/">pattern Registry</a> и <a href="http://mabp.kiev.ua/2008/05/02/pattern_service_locator/">pattern ServiceLocator</a>
</p>
<span id="more-999">
</span>
<pre>
<code class="php">

class Singleton {
	private static $instance; // object


	/**
	 * Private constructor does nothing
	 *
	 */
	final private function __construct(){
		/* ... */
	}


	/**
	 * Return the single instance of object
	 *
	 * @return object
	 */
	public static function &#038; __instance(){
		if (!isset(self :: $instance))
			self :: $instance = new self;
		return self :: $instance;
	}
}


$single = Singleton::__instance();

</code>
</pre>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/04/04/pattern-singleton/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wordpress: плагин переводчик заголовков</title>
		<link>http://mabp.kiev.ua/2009/03/28/wordpress-plugin-title-translator/</link>
		<comments>http://mabp.kiev.ua/2009/03/28/wordpress-plugin-title-translator/#comments</comments>
		<pubDate>Sat, 28 Mar 2009 15:36:35 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=962</guid>
		<description><![CDATA[Позавчера можно сказать девственности лишился, написал свой первый плагин под WordPress. Функционал не сложный, но нужный. Когда сохраняешь статью ссылка делается из названия с удалением всяких нецензурных символов и заменой пробелов на тире. Но никто же своим страницам не даёт русские ссылки, это плохо во-первых для SEO, а во-вторых просто не читабельно потому что буквы [...]]]></description>
			<content:encoded><![CDATA[<p>Позавчера можно сказать девственности лишился, написал свой первый плагин под <a href="http://mabp.kiev.ua/tag/wordpress/">WordPress</a>. Функционал не сложный, но нужный. Когда сохраняешь статью ссылка делается из названия с удалением всяких нецензурных символов и заменой пробелов на тире. Но никто же своим страницам не даёт русские ссылки, это плохо во-первых для <a href="http://mabp.kiev.ua/tag/seo/">SEO</a>, а во-вторых просто не читабельно потому что буквы преобразуются в ASCII коды, да еще и по 6 символов на букву! Так например слово 'бля' будет зашифровано как %d0%b1%d0%bb%d1%8f. А переводить каждый раз руками все заголовки лень, вот я и прикрутил свой <a href="http://mabp.kiev.ua/2008/08/28/google_translate/">Google Transtator</a> к <a href="http://mabp.kiev.ua/tag/wordpress/">WordPress'у</a>.</p>
<span id="more-962">
</span>
<p>Естественно я сначала попытался найти плагин реализующий подобный функционал в репозитории <a href="http://mabp.kiev.ua/tag/wordpress/">WordPress'а</a>, но там был только перевод с китайского на английский, что мне немного не подходило ;). Поскольку опыта в написании плагинов под <a href="http://mabp.kiev.ua/tag/wordpress/">WordPress</a> у меня не было я взял за основу именно этот плагин выкинув из него все лишнее, на мой взгляд и дополнив его своим <a href="http://mabp.kiev.ua/2008/08/28/google_translate/">Google Transtator'ом</a>. Получилось я думаю не очень плохо, зато я переписал его под <a href="http://mabp.kiev.ua/category/programming/php/">PHP5</a>и поправил объектную модель. Все что у меня получилось вы можете увидеть ниже.</p>
<pre>
<code class="php">

&lt;?php
/*
Plugin Name: TitleTranslate
Plugin URI: http://mabp.kiev.ua/2009/03/28/wordpress-plugin-title-translator/
Version: 1.0
Description: Translate title fot permanent link
Author: CTAPbIu_MABP
Author URI: http://mabp.kiev.ua/
*/


if(!class_exists('TitleTranslate')):
class TitleTranslate{
	private $slug_name;
	private $slug_title;


	public function __construct($wp_version){
		add_filter('title_save_pre', array(&#038;$this,'get_from_title'), 0);
		add_filter('name_save_pre', array(&#038;$this,'put_to_name'), 0);
		if($wp_version &gt; 2.4 &#038;&#038; strpos($_SERVER['REQUEST_URI'], 'admin-ajax.php') &#038;&#038; $_POST['action'] === 'sample-permalink'){
			add_filter('sanitize_title', array(&#038;$this,'ajax_slug'),0);
		}
	}


	public function ajax_slug($name){
		remove_filter('sanitize_title', array(&#038;$this,'ajax_slug'), 0);
		$name = $this-&gt;put_to_name($name);
		add_filter('sanitize_title', array(&#038;$this,'ajax_slug'), 0);
		return $name;
	}


	public function get_from_title($title){
		$this-&gt;slug_name = '';
		$this-&gt;slug_title = $title;
		return $title;
	}


	public function put_to_name($name){


		if(!empty($this-&gt;slug_name))
			return $this-&gt;slug_name;


		if(empty($name) &#038;&#038; !empty($this-&gt;slug_title))
			$name = $this-&gt;slug_title;


		$translation = $this-&gt;translate($name);
		$translation = sanitize_user(sanitize_title($translation), true);
		return $translation ? $translation : $name;
	}


	public function translate($str, $from='ru', $to='en'){
		$fp = fsockopen("www.google.com", 80, $errno, $errstr, 30);
		if (!$fp) {
			//trigger_error("$errstr ($errno)&lt;br /&gt;\n", E_USER_WARNING);
			return "";
		} else {
			$out = "GET /translate_a/t?client=t&#038;sl=".$from."&#038;tl=".$to."&#038;text=".urlencode($str)." HTTP/1.1\r\n";
			$out .= "Host: www.google.com\r\n";
			$out .= "User-Agent: Mozilla/5.0\r\n";
			$out .= "Accept-Encoding: deflate\r\n";
			$out .= "Connection: Close\r\n\r\n";


			fputs($fp, $out);
			$res = "";
			while (!feof($fp)) {
				$res .=  fgets($fp, 1024);
			}
			fclose($fp);
		}


		$res = explode("\r\n\r\n",$res);
		$res = explode("\r\n",$res[1]);
		return substr($res[1],0,1) == '[' ?
			substr($res[1],2,strpos($res[1],'"',2)-2) :
			substr($res[1],1,-1);
	}
}
endif;


new TitleTranslate($wp_version);
?&gt;

</code>
</pre>
<p>А если кто-то захочет <a href="http://mabp.kiev.ua/content/source/TitleTranslate.phps" title="source code" rel="nofollow">скачать</a> то вот ссылка на файл. Устанавливается так же как и все остальные плагины копированием *.php файла в папку wp-content/plugins.</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/03/28/wordpress-plugin-title-translator/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Счастливый билетик</title>
		<link>http://mabp.kiev.ua/2009/03/07/lucky-coupon/</link>
		<comments>http://mabp.kiev.ua/2009/03/07/lucky-coupon/#comments</comments>
		<pubDate>Sat, 07 Mar 2009 12:03:26 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[algorithms]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=813</guid>
		<description><![CDATA[Вчера речь зашла о 'счастливых талончиках', если кто на общественном транспорте не ездит то это такие талончики у которых серийный номер состоит из 6 цифр и сумма первых трёх равна сумме последних трёх. Так вот стало очень интересно какая вероятность того что тебе попадется 'счастливый талончик', для этого я решил написать функцию на PHP, но [...]]]></description>
			<content:encoded><![CDATA[<p>Вчера речь зашла о 'счастливых талончиках', если кто на общественном транспорте не ездит то это такие талончики у которых серийный номер состоит из 6 цифр и сумма первых трёх равна сумме последних трёх. Так вот стало очень интересно какая вероятность того что тебе попадется 'счастливый талончик', для этого я решил написать функцию на <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a>, но Apache под руками не оказалось и я написал на <a href="http://mabp.kiev.ua/category/programming/javascript/">JavaScript</a>. Сначала я думал что оптимальный алгоритм это разделение строки на две части, сложение цифр первой и второй половины, и сравнение.</p>
<span id="more-813">
</span>
<pre>
<code class="javascript">

function is_lucky(num){
	num = num.toString(); // на всякий случай
	var l = num.length, part = [], sum = [0,0];
	if (l%2 || !/^[0-9]+$/.test(num))
		return false;
	part[0] = num.substring(0,l/2).split("");
	part[1] = num.substring(l/2,l).split("");
	for(var i in part)
		for(var j in part[i])
			sum[i] += parseInt(part[i][j]);
	return sum[0] == sum[1];
}

</code>
</pre>
<p>Но потом когда я думал как бы это выглядело на <a href="http://mabp.kiev.ua/category/programming/java/">Java</a>, я нашел способ попроще. Достаточно сложить все числа первой половины и отнять от полученного все числа второй половины, если в результате ноль то билетик счастливый.</p>
<pre>
<code class="javascript">

function is_lucky(num){
	var l = num.length, sum = 0;
	if (l%2 || !/^[0-9]+$/.test(num))
		return false;
	for(var i in num)
		sum += parseInt(num[i]) * (i&lt;l/2?1:-1);
	return !sum;
}

</code>
</pre>
<p>Реализация на PHP</p>
<pre>
<code class="php">

function is_lucky($num){
	$l = strlen($num);
	$sum = 0;
	if ($l%2 || !preg_match("/^[0-9]+$/", $num))
		return false;
	for($i=0;$i&lt;$l;$i++)
		$sum += $num[$i] * ($i&lt;$l/2?1:-1);
	return !$sum;
}

</code>
</pre>
<p>А еще я подумал что раз уж <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a> и <a href="http://mabp.kiev.ua/category/programming/javascript/">JavaScript</a> языки нетипизированные то стоит проверять что засунули в функцию и добавил туда регулярку /^[0-9]+$/</p>
<p>Реализация на Java</p>
<pre>
<code class="java">

package ua.kiev.mabp;


/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 07.03.2009
 * Time: 11:40:21
 */


public class LuckyCoupon {
    public static void main(String[] args) {
        System.out.print(isLucky(463571));
    }


    public static Boolean isLucky(Integer num) {
        char[] c = num.toString().toCharArray();
        int sum=0;
        for (int i=0,l=c.length;i&lt;l;i++)
            sum += c[i] * (i&lt;l/2?1:-1);
        return sum==0;
    }
}

</code>
</pre>
<p>Но вернемся к тому зачем нам это нужно было, а нужно было посчитать количество счастливых билетиков. Для этого чуть усложним наш класс добавив в метод main цикл и дополнительный метод который из числа в формате '123' сделает число в формате '000123' и передаст на обработку уже имеющемуся методу для проверки.</p>
<pre>
<code class="java">

package ua.kiev.mabp;


/**
 * Created by IntelliJ IDEA.
 * User: CTAPbIu_MABP
 * Date: 07.03.2009
 * Time: 11:40:21
 */


public class LuckyCoupon {
    public static void main(String[] args) {
        int counter = 0;
        for(int i=0;i&lt;1000000;i++)
            if (isLucky(i))
                counter++;
        System.out.print(counter);
    }


    public static Boolean isLucky(Integer num) {
        int l = 6 - num.toString().length();
        String str = "";
        for (int i=0;i&lt;l;i++)
            str += "0";
        return isLucky(str+num);
    }


    public static Boolean isLucky(String num) {
        char[] c = num.toCharArray();
        int sum=0, i=0, l=c.length;
        while (i&lt;l)
            sum += c[i] * (i++&lt;l/2?1:-1);
        return sum==0;
    }
}

</code>
</pre>
<p>В результате получим число 55252, далее пользуясь только калькулятором узнаем что 55252/1000000*100 = 5,5252% . То есть вероятность получить из рук кондуктора счастливый билетик чуть более чем пять с половиной процентов, а те кто играет в линейку или вов знают что это достаточно большой шанс.</p>
<p>Но удивляет другое удивляет симметричность появления таких числе, я хотел нарисовать график, но подумал что график на 1000 позиций будет очень большим поэтому приведу тут только часть матрицы. Ах да матрицы... Матрица получается в том случаи если посчитать сколько 'счастливых талончиков' в каждой тысяче, и записывать в ряд делая обрыв строки после каждого значения. В общем не с моим талантом объяснять смотрите и запускайте код. Этим надо заменить метод main из прошлого примера.</p>
<pre>
<code class="java">

    public static void main(String[] args) {
        int counter = 0;
        Integer[] num = new Integer[1000];
        for(int i=0;i&lt;1000000;i++)
            if (isLucky(i)){
                counter++;
                Integer d = ((Double)Math.floor(i++/1000)).intValue();
                if (num[d] == null)
                    num[d] = 0;
                num[d]++;
            }
        for (int i=0;i&lt;1000;i++){
            String str = num[i].toString();
            System.out.print((str.length()&lt;2?"0"+str:str) + (i%10==9?"\n":" "));
        }
    }

</code>
</pre>
<p>Так вот вернемся к матрице, она получаеться вот такая</p>
<pre>

01 03 06 10 15 21 28 36 45 55
03 06 10 15 21 28 36 45 55 63
06 10 15 21 28 36 45 55 63 69
10 15 21 28 36 45 55 63 69 73
15 21 28 36 45 55 63 69 73 75
21 28 36 45 55 63 69 73 75 75
28 36 45 55 63 69 73 75 75 73
36 45 55 63 69 73 75 75 73 69
45 55 63 69 73 75 75 73 69 63
55 63 69 73 75 75 73 69 63 55

</pre>
<p>Cледующая часть будет начинаться с 03 (06, 10, 15 ...) и заканчиваться на 63 (69, 73, 75...), тоесть самый правый столбик с каждым цыклом переходит в первый ряд и так пока 01 не окажеться в правом нижнем углу.</p>
<p>А в школе мне математика была не интересна...</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/03/07/lucky-coupon/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>break $me;</title>
		<link>http://mabp.kiev.ua/2009/01/24/break-me/</link>
		<comments>http://mabp.kiev.ua/2009/01/24/break-me/#comments</comments>
		<pubDate>Sat, 24 Jan 2009 11:05:44 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Голоса в голове]]></category>
		<category><![CDATA[Программирование]]></category>

		<guid isPermaLink="false">http://mabp.kiev.ua/?p=518</guid>
		<description><![CDATA[Удивительно что такое большое количество людей не знает, что оператор break в PHP может принимать параметр который указывает какое количество вложенных циклов нужно остановить. Более того он может принимать переменную, что вряд ли полезно, но радует наличием возможности. Об этом мелким шрифтом написано в мануале, но судя по количеству кода, где я видел его использование, [...]]]></description>
			<content:encoded><![CDATA[<p>Удивительно что такое большое количество людей не знает, что оператор break в <a href="http://mabp.kiev.ua/category/programming/php/">PHP</a> может принимать параметр который указывает какое количество вложенных циклов нужно остановить. Более того он может принимать переменную, что вряд ли полезно, но радует наличием возможности. Об этом мелким шрифтом написано в мануале, но судя по количеству кода, где я видел его использование, даже самые одаренные гуру читают ман по диагонали.</p>
<span id="more-518">
</span>
<pre>
<code class="php">

while(true){
	for($_=array(4);;){
		foreach($_ as $val){
			switch($_[]=$val){
				default:
					break $val;
			}
		}
	}
}

</code>
</pre>
<p>В примере $_ использовано для того чтобы сделать цикл foreach бесконечным, а switch добавлен просто для красоты примера, можно было бы еще do{}while(); добавить, но по-моему простого while вполне достаточно.</p>
<p>А вместо этого начинаются всякие пляски с бубном типа:</p>
<pre>
<code class="php">

for($break=false;;){
	for(;;){
		$break=true;
		break;
	}
	if($break){
		break;
	}
}

</code>
</pre>
<p>Можно же  как минимум красивее написать...</p>
<pre>
<code class="php">

for($break=false;!$break;){
	for(;!$break;){
		$break=true;
	}
}

</code>
</pre>
<p>Эта конструкция по большому счету эквивалентна label в <a href="http://mabp.kiev.ua/category/programming/java/">Java</a> и <a href="http://mabp.kiev.ua/category/programming/javascript/">JavaScript</a>
</p>
<pre>
<code class="java">

label:
for (;;) {
	for (;;) {
		break label;
	}
}

</code>
</pre>
<p>Оператор continue работает точно также!</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2009/01/24/break-me/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Google Translate</title>
		<link>http://mabp.kiev.ua/2008/08/28/google_translate/</link>
		<comments>http://mabp.kiev.ua/2008/08/28/google_translate/#comments</comments>
		<pubDate>Thu, 28 Aug 2008 16:15:14 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=221</guid>
		<description><![CDATA[Сейчас пытаюсь возродить свой бывший сайт под названием ForbidenWish. Там много книг и вносить их в БД вручную я не собираюсь, поэтому написал небольшой скрипт который обходит директории, парсит имена файлов и заносит их в базу. Вот в один момент я понял что простая транслитерация названия книги это не интересно, а иногда и глупо получалось, [...]]]></description>
			<content:encoded><![CDATA[<p>Сейчас пытаюсь возродить свой бывший сайт под названием ForbidenWish. Там много книг и вносить их в БД вручную я не собираюсь, поэтому написал небольшой скрипт который обходит директории, парсит имена файлов и заносит их в базу. Вот в один момент я понял что простая транслитерация названия книги это не интересно, а иногда и глупо получалось, и я вспомнил про форум ДКлаб у них там при создании темы заголовок переводиться на английски (причем весьма неплохо) и подставляется в url. Я практически уверен что Котеров не писал переводчик и просто пользуется каким-то сервисом, первое что мне пришло в голову - Google. Сначала думал парсить html страницу но потом понял что там все намного проще и перевод забирается <a href="http://mabp.kiev.ua/category/programming/javascript/">javascript'ом</a>, В общем после непродолжительных изысканий я придумал вот эту функцю.</p>
<span id="more-221">
</span>
<pre>
<code class="php">

function translate($str, $from='ru', $to='en'){
	$fp = fsockopen("www.google.com", 80, $errno, $errstr, 30);
	if (!$fp) {
		trigger_error("$errstr ($errno)&lt;br /&gt;\n", E_USER_WARNING);
		return "";
	} else {
		$out = "GET /translate_a/t?client=t&#038;sl=".$from."&#038;tl=".$to."&#038;text=".urlencode($str)." HTTP/1.1\r\n";
		$out .= "Host: www.google.com\r\n";
		$out .= "User-Agent: Mozilla/5.0\r\n";
		$out .= "Accept-Encoding: deflate\r\n";
		$out .= "Connection: Close\r\n\r\n";


		fputs($fp, $out);
		$res = "";
		while (!feof($fp)) {
			$res .=  fgets($fp, 1024);
		}
		fclose($fp);
	}


	$res = explode("\r\n\r\n",$res);
	$res = explode("\r\n",$res[1]);
	return stripslashes(substr($res[1],1,-1));
}

</code>
</pre>
<p>Но таким образом гугл отказывается переводить больше чем 2 килобайта текста, если нудно переводить большие объемы по нужно использовать пост запрос</p>
<pre>
<code class="php">

function translate($str, $from='en', $to='ru'){
	$fp = fsockopen("www.google.com", 80, $errno, $errstr, 30);
	if (!$fp) {
		trigger_error("$errstr ($errno) \n", E_USER_WARNING);
		return "";
	} else {
		$text = "text=".urlencode($str);
		$out = "POST /translate_a/t?client=t&#038;sl=".$from."&#038;tl=".$to." HTTP/1.1\r\n";
		$out .= "Host: www.google.com\r\n";
		$out .= "User-Agent: Mozilla/5.0\r\n";
		$out .= "Accept-Encoding: deflate\r\n";
		$out .= "Content-length: ".strlen($text)."\r\n";
		$out .= "Connection: Close\r\n\r\n";
		$out .= $text;


		fputs($fp, $out);
		$res = "";
		while (!feof($fp)) {
			$res .=  fgets($fp, 1024);
		}
		fclose($fp);
	}


	$res = explode("\r\n\r\n",$res);
	$res = explode("\r\n",$res[1]);
	return stripslashes(substr($res[1],1,-1));
}

</code>
</pre>
<p>Так можно обработать до 32 килобайт за раз!</p>
<p>Если кому пригодиться - оставьте коммент!</p>
<p>
<strong>UPD</strong> Реализация на <a href="http://mabp.kiev.ua/category/programming/cpp/">С++</a> от Lupascu Ion с небольшой доработкой от меня</p>
<pre>
<code class="cpp">

String GoogleTranslator::TranslateText(String from, String to){
	//... need to add proxy
	//http_client.Proxy("");
	String url = "www.google.com/translate_a/t?client=t&#038;sl=" + from + "&#038;tl=" + to + "&#038;ie=utf-8&#038;oe=utf-8";
	http_client.URL(url);
	//http_client.Agent("Mozilla/5.0");
	http_client.TimeoutMsecs(5000);
	http_client.Post();
	http_client.PostData(String("text=").Cat()&lt;&lt;UrlEncode(inputwindow.textfrom.Get(CHARSET_UTF8)));
	//http_client.Headers("Accept-Encoding: deflate\r\n");
	String result = http_client.ExecuteRedirect();


	if (!IsNull(result)){
		if(result.StartsWith("\"")){// is string
			result.Remove(0, 1);
			result.Remove(result.GetLength()-1, 1);
		}
		else{ // is terms
			//... need to parse terms
		};


		return result;
	}
	else
		return String("Error:").Cat()&lt;&lt;Nvl(http_client.GetError(), "")
			&lt;&lt;"\n, status: "&lt;&lt;http_client.GetStatusCode()&lt;&lt;", "&lt;&lt;http_client.GetStatusLine()
			&lt;&lt;"\n, header: "&lt;&lt;http_client.GetHeaders();
}

</code>
</pre>
<p>
<strong>UPD</strong> Есть предложение вместо </p>
<pre>
<code class="php">

return stripslashes(substr($res[1],1,-1));

</code>
</pre>
<br />
возвращать<br />
<pre>
<code class="php">

return json_decode($res[1]);

</code>
</pre>
<br />
Но на этом сраном хостинге с тех пор как им занимается компания HostBizUa перестали ставить свежие версии ПО, и у меня стоит древний <a href="http://mabp.kiev.ua/category/programming/php/">PHP 5.1.6</a> в котором этой функции нет, поэтому я использую такое мудачество чтобы со словарем проблем не было.<br />
<pre>
<code class="php">

return substr($res[1],0,1) == '[' ?
	substr($res[1],2,strpos($res[1],'"',2)-2) :
	substr($res[1],1,-1);

</code>
</pre>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/08/28/google_translate/feed/</wfw:commentRss>
		<slash:comments>105</slash:comments>
		</item>
		<item>
		<title>Pattern: ServiceLocator</title>
		<link>http://mabp.kiev.ua/2008/05/02/pattern_service_locator/</link>
		<comments>http://mabp.kiev.ua/2008/05/02/pattern_service_locator/#comments</comments>
		<pubDate>Fri, 02 May 2008 16:04:39 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[JAVA]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[pattern]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=205</guid>
		<description><![CDATA[





Статья Pattern: Registry имеет непосредственно отношение к этой статье, советую ознакомиться перед прочтением.



Паттерн ServiceLocator изначально спроектирован для Java и дает возможность находить сервисы, зная их имя. В Java для того чтоб найти Enterprise JavaBeans (EJB) или Java Message Service (JMS) нужно использовать JNDI API. Это накладывает на код некоторые ограничения, например операции поиска и создания [...]]]></description>
			<content:encoded><![CDATA[<table style="background-color:#EDEFF0;width:100%;">
<tbody>
<tr>
<th>
<img src="/wp-content/themes/inove/img/warning_yellow.png"/>
</th>
<th style="text-align: center;">Статья <a href="http://mabp.kiev.ua/2008/04/17/registry/" title="Pattern: Registry">Pattern: Registry</a> имеет непосредственно отношение к этой статье, советую ознакомиться перед прочтением.</th>
</tr>
</tbody>
</table>
<p>Паттерн ServiceLocator изначально спроектирован для Java и дает возможность находить сервисы, зная их имя. В Java для того чтоб найти Enterprise JavaBeans (EJB) или Java Message Service (JMS) нужно использовать JNDI API. Это накладывает на код некоторые ограничения, например операции поиска и создания компонентов служб могут быть сложными (ресурсоемкими) и могут использоваться периодически в различных клиентах приложения. Для этого ввели паттерн, который позволяет абстрагироваться от использования JNDI и скрытия сложностей создания исходного контекста, а также может повторно использоваться несколькими клиентами.</p>
<span id="more-205">
</span>
<p>Но поскольку для PHP это все недоступно, мы будем искать объекты для одного клиента, абстрагируясь от их создания и места расположения классов их описывающих. Мы будем использовать ту же модель иерархии и связей, что и Java но с поправками на угловатости PHP. </p>
<p>На картинке изображена диаграмма последовательности действий, показывающая взаимодействия между различными участниками ServiceLocator</p>
<img src="/content/img/servicelocator.gif" alt="Диаграмма взаимодействия между участниками ServiceLocator">
<p>Итак задача получить объект страницы для дальнейшего использования, зная только название объекта.</p>
<p>Для этого нам понадобиться четыре класса и три исключения порождаемых этими классами. Я думаю, начать стоит именно с этих трех исключений, поскольку смысловой нагрузки они пока не несут, а являются лишь абстракциями для дальнейшей реализации и внесены в код для его схожести с Java.</p>
<pre>
<code class="php">

class ServiceLocatorExeption extends  Exception{
}


class InitialContextException extends  Exception{
}


class PageFactoryExeption extends  Exception{
}

</code>
</pre>
<p>Далее я бы хотел начать с конца, потому что чем дальше от начала тем сильнее уровень абстракции и меньше кода. Поэтому сервис (объект), который мы собственно пытаемся получить, в примере не имплементирует никаких интерфейсов и не расширяет никаких классов и не имеет никаких методов, а буквально состоит из своего названия. Это вполне достаточно чтобы удачно создать его экземпляр и вернуть клиенту. Кстати роль клиента тоже весьма условна, ее играет сам PHP скрипт и из-за того, что после завершения скрипта все объекты разрушаются нельзя говорить ни о каком повторном использовании созданных объектов. Единственным способом что-то использовать повторно является кэширование, основанное на БД или файлах или сессии, но при текущей задаче это слушком дорогая (время и ресурсоемкая) процедура и она не рассматривается.</p>
<pre>
<code class="php">

class WhitePage{


}

</code>
</pre>
<p>Как понятно из названия искать мы будем объект страницы, возможно чтобы ассоциировать с ним какой-то контент, а возможно для того чтобы передать его шаблонизатору для отображения.</p>
<p>Второй объект с конца у нас фабрика которая должна создать или найти уже готовый объект страницы. Лично мое мнение, что фабрика должна быть статическим классом (классом в котором все методы статические), и через конструктор вообще не должна создаваться. Но в этом примере она будет именно создаваться, а еще и получая параметры, пришедшие в виде контекста.</p>
<pre>
<code class="php">

class PageFactory{
	public $initialContext = null;


	public function __construct($initialContext){
		$this->initialContext = $initialContext;
	}


	public function &#038; factory(){
		try{
			// do somethind depends on $initialContext
			$product =  new WhitePage();
		}catch (Exception $e){
			throw new PageFactoryExeption();
		}


		return $product;
	}
}

</code>
</pre>
<p>Единственный метод (кроме конструктора) этой фабрики основываясь на пришедшем контексте должен выбрать какой объект он будет создавать, это может быть страница с текстом страница с уведомлением об ошибке, список страниц, или список списков. на данный момент это не важно поскольку у нас есть только "белая страница" с которой можно будет сделать все что угодно, даже распечатать и повесить в туалете.</p>
<p>Соответственно если создание не удалось, то бросается исключение, которое потом будет проброшено в сам ServiceLocator.</p>
<p>Идем дальше по цепочке. Следующий у нас объект InitialContext, который при создании должен получать в себя все доступные переменные окружения, и тоже имеет один метод (естественно кроме конструктора) который осуществляет поиск нужной фабрики и передаче ей переменных окружения, сама же фабрика возвращается в сам ServiceLocator.</p>
<pre>
<code class="php">

class InitialContext{
	private $data;
	public function __construct(){
		 // do something depends on 
		 // $_GET, $_POST, $_COOKIE, $_FILES, $_SESSION, etc
		 if(isset($_SESSION))
		 	$this->data = $_SESSION;
		 else 
		 	$this->data = $_REQUEST;
	}


	public function &#038; lookup($name){
		$factoryName = ucfirst($name)."Factory";
		try{
			$factory = new $factoryName($this->data);	
		}catch (Exception $e){
		/*
			try{
				$factoryName::getInstance();
			}catch(Exception $ee){
				throw new InitialContextException();
			}
		*/
			throw new InitialContextException();
		}
		return $factory;
	}
}

</code>
</pre>
<p>Тут очень хотелось в блоке catch сделать еще один try для попытки получения инстанса у синглтон объекта, но его пришлось закомментировать потому что PHP поддерживает конструкцию $factoryName::getInstance() только начиная с версии 5.3. В предыдущих версиях название класса должно быть указанно непосредственно. Разработчики объясняют это тем, что при начале синтаксического разбора все статические вызовы преобразуются в функции.</p>
<p>Ну и наконец то мы добрались до сладенького. То есть до самой реализации ServiceLocator. По наставлению Java класс реализовывает <a href="http://mabp.kiev.ua/2009/04/04/pattern-singleton/">паттерн Singleton</a> и имеет метод getService принимающий название сервиса и возвращающий сам сервис. Больше пока ничего нет, да ничего и не будет, наверное, потому что получать id объекта, а потом восстанавливать его по этому id неоткуда.</p>
<pre>
<code class="php">

class ServiceLocator{
	private static $instance = null;
	private static $initialContext = null;


    final private function __construct(){
    	try {
    		$this->initialContext = new InitialContext();
    	}catch (Exception $e){
    		throw new ServiceLocatorExeption();	
    	}
    } 


	static function &#038; getInstance(){ 
        if (!isset(self :: $instance)) 
            self :: $instance = new self; 
        return self :: $instance; 
    }


	public function &#038; getService($name){
		if (empty($name))
			throw new ServiceLocatorExeption();


		try{
			$serviceFactory = $this->initialContext->lookup($name);
			$service = $serviceFactory->factory();
		}catch (InitialContextException $e){
			throw new ServiceLocatorExeption();
		}catch (PageFactoryExeption $e){
			throw new ServiceLocatorExeption();
		}


		return $service;	
	}
}

</code>
</pre>
<p>Ну я думаю тут тоже ничего сложного нет. Приватный конструктор при единственном вызове создает InitialContext и сохраняет его. getInstance обеспечивает доступ к инстансу, а getService запускает всю вышеописанную цепочку и возвращает нам нашу белую страничку. Для запуска все этого добра требуется всего две строчки:</p>
<pre>
<code class="php">

$serviceLocator = ServiceLocator::getInstance();
var_dump($serviceLocator->getService("page"));
// object(WhitePage)#4 (0) { }

</code>
</pre>
<p>Вообще эта статья была написана в поисках того как можно объединить <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерн Registry</a> и Pattern ServiceLocator. Вышло следующее, но реально применять на сайте я пока не стал из-за отсутствия наличия PHP 5.3 на сервере.</p>
<pre>
<code class="php">



class PageFactory{
	public $initialContext = null;


	public function __construct(){
		 if(isset($_SESSION))
		 	$this->initialContext = $_SESSION;
		 else 
		 	$this->initialContext = $_REQUEST;
	}


	public function &#038; factory(){
		try{
			// do something depends on $initialContext
			$product =  new WhitePage();
		}catch (Exception $e){
			throw new PageFactoryExeption();
		}


		return $product;
	}
}



</code>
</pre>
<p>Классом InitialContext я пожертвовал, решив, что он лишний в этой пищевой цепочке и переложил его функции частично на класс PageFactory и частично на ServiceLocator::factory. Новый ServiceLocator основан на всем, что было в <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерн Registry</a>, по сути, добавляя только один новый метод getObjId. Метод getService является синонимом register с той лишь разницей, что добавляет уникальный идентификатор и дает хранить несколько объектов одного типа. Метод getObj это обертка для extract. А вот метод getObjId это уникальная плюшка класса ServiceLocator которая дает возможность получать id имея объект, операция противоположная для getObj. И, наконец переписан метод factory добавляя дополнительную возможность создания объекта через его фабрику. Например, если есть page но не известно как его создать сначала будет создана фабрика PageFactory, а потом будет попытка создать из нее что-нибудь, используя метод factory.</p>
<pre>
<code class="php">

require_once("class.registry.php");


class ServiceLocator extends Registry {


	/**
	 * Looks up for services
	 *
	 * @param string $name
	 * @return mixed
	 */
	static public function &#038; getService($name){
		$id = md5(time());
		$service = self::register($name,$id);
		return $service;
	}


	/**
	 * Restore object by id
	 *
	 * @param string $id
	 * @return mixed
	 */
	static public function &#038; getObj($id){
		return self::extract($id);	
	}	


	/**
	 * extracts object id
	 *
	 * @param mixed $obj
	 * @return string
	 */
	static public function &#038; getObjId($obj){
		$reg = self::__instance();
		// array_search($obj, $reg->tools) ???
		foreach ($reg->tools as $key => &#038;$val)
			if($obj === $val)
				break;
		return $key;
	}


	/**
	 * Implementation of factory pattern
	 *
	 * @param string $name
	 * @param array $param
	 * @param string $func
	 * @return object
	 */
	static public function &#038; factory($name,$params=null,$func="__instance"){


		if (is_object($name)) 
			return $name;


		if (!class_exists($name) &#038;&#038; is_callable("__autoload"))
			__autoload($name);


		if (class_exists($name)){
			if(is_callable(array($name,$func))){
				return call_user_func_array(array($name,$func),$params); // метод $name::$func вызван статично
			}else if(!$params){ // пытаемся сэкономить время
				return new $name();
			}else{
				$reflection = new ReflectionClass($name);
				return $reflection->newInstanceArgs($params);
			}
		}else{
			$factory = ucfirst($name)."Factory";


			if (!class_exists($factory) &#038;&#038; is_callable("__autoload"))
				__autoload($factory);


			if(class_exists($factory) &#038;&#038; is_callable(array($factory,"factory"),true)){
				return call_user_func_array(array($factory,"factory"),$params);
			}
		}
		// если мы до сюда дошли и ничего не вернули то бросаем исключение
		throw new Exception("Class '$name' doesn't declared and can't be loaded so does it's factory");


	}
}

</code>
</pre>
<p>Прежде чем вы попробовали запустить этот код, спешу заметить что работать код будет только на PHP 5.3, хотя сам я пока не проверял. По причине указанной выше статические методы классов наследников не перезаписывают статические методы классов родителей. Для того чтобы пример заработал нужно добавить новые методы в класс <a href="http://mabp.kiev.ua/2008/04/17/pattern-registry/">паттерн Registry</a> и переписать метод factory.</p>
<br />
]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/05/02/pattern_service_locator/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Наконец-то заработал поиск</title>
		<link>http://mabp.kiev.ua/2008/04/26/search_engine_works_now/</link>
		<comments>http://mabp.kiev.ua/2008/04/26/search_engine_works_now/#comments</comments>
		<pubDate>Sat, 26 Apr 2008 15:47:10 +0000</pubDate>
		<dc:creator>CTAPbIu_MABP</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[Программирование]]></category>
		<category><![CDATA[perfomance]]></category>

		<guid isPermaLink="false">http://mabp.localhost/?p=196</guid>
		<description><![CDATA[





Статья более не актуальна, так как относилась к старому, самописному движку.



Вот я и сделал наконец поиск по сайту, вообще еще много чего надо сделать, а то я даже страницы добавляю через MySQL. Сейчас поиск ищет по заголовку, описанию и собственно телу страницы, самое приятное в нем то, что в нем есть ранжирование результатов. Если кому-то [...]]]></description>
			<content:encoded><![CDATA[<table style="background-color:#EDEFF0;width:100%;">
<tbody>
<tr>
<th>
<img src="/wp-content/themes/inove/img/warning_red.png"/>
</th>
<th style="text-align: center;">Статья более не актуальна, так как относилась к старому, самописному движку.</th>
</tr>
</tbody>
</table>
<p>Вот я и сделал наконец поиск по сайту, вообще еще много чего надо сделать, а то я даже страницы добавляю через MySQL. Сейчас поиск ищет по заголовку, описанию и собственно телу страницы, самое приятное в нем то, что в нем есть ранжирование результатов. Если кому-то интересно как такое сделать то читайте дальше.</p>
<span id="more-196">
</span>
<p>MATCH() ... AGAINST() первое, что приходит в голову, когда говорят о поиске с релевантностью, забудьте об этом бреде!!! Во-первых, это накладывает очень два ограничений: первое и главное - надо делать полнотекстовые индексы, без них никак, второе - индексы можно сделать только на таблицах MyISAM. Во вторых это просто глючно, потому что при поиске небольших фраз по большой базе их релевантность близка к абсолютному нулю, или же если слово присутствует в более 50% строк, то оно не учитывается.</p>
<pre>
<code class="sql">

SELECT 
MATCH('Content') AGAINST ('keyword1 keyword2') as Relevance 
FROM table 
WHERE MATCH ('Content') AGAINST('+keyword1 +keyword2' IN BOOLEAN MODE) 
HAVING Relevance > 0.2 
ORDER BY Relevance DESC

</code>
</pre>
<p>Это так сказать классический способ поиска, взятый с сайта самого мускула, но ИМХО это большая ошибка, тут первый MATCH выдает релевантность, а второй который IN BOOLEAN MODE используется для поиска обоих слов сразу в одной строке, если есть только одно то он выдаст 0. Если слов больше двух то это начинает давать сильную погрешность, выдавая только те ряды, где есть все слова фразы. Более того, куча MATCH сильно тормозит запрос.</p>
<p>Поэтому лучше ввести весовые коэффициенты в запрос. Коэффициенты вы раздаете сами, поэтому их общее число всегда может быть в пределах 100 и к нему можно смело добавлять знак %. Итак у нас есть три колонки title, description и text. Если в каждом из трех полей есть искомое словосочетание то релевантность 100%, при этом каждое поле имеет свой вес: заголовок - самый большой(40%), потом описание(20%) а потом уже текст(10%). Я считаю, что полное словосочетание это 70% релевантности и если есть все слова из него, то это еще 30%. немного запутал, сейчас объясню. Есть словосочетание "мама мыла раму", если оно дословно есть во всех полях то это 70%, а если в каждом из них есть "раму мыла мама", то это только 30%. В результате мы получаем либо 100% (70% все вместе и 30% каждое по отдельности) совпадение со строкой либо только 30% (каждое по отдельности) совпадение, ну это лично мое мнение.</p>
<p>Итак алгоритм будет выгладить следующим образом:</p>
<pre>
<code class="php">

$text = "мама мыла раму";
$query = "SELECT *, 
IF (title like '%".$text."%', 40, 0) + IF (title LIKE '%".str_replace(" ", "%', 5.71, 0) + IF (title LIKE '%", $text)."%', 5.71, 0) + 
IF (description like '%".$text."%', 20, 0) + IF (description LIKE '%".str_replace(" ", "%', 2.86, 0) + IF (description LIKE '%", $text)."%', 2.86, 0) +
IF (text like '%".$text."%', 10, 0) + IF (text LIKE '%".str_replace(" ", "%', 1.43, 0) + IF (text LIKE '%", $text)."%', 1.43, 0) AS rel
FROM pages 
WHERE 
(title LIKE '%".str_replace(" ", "%' OR title LIKE '%", $text)."%') OR
(description LIKE '%".str_replace(" ", "%' OR description LIKE '%", $text)."%') OR
(text LIKE '%".str_replace(" ", "%' OR text LIKE '%", $text)."%') 
ORDER BY rel DESC";

</code>
</pre>
<p>Если подставить значения будет выглядеть менее запутано но все равно непонятно </p>
<pre>
<code class="sql">

SELECT *, 
IF (title LIKE '%мама мыла раму%', 40, 0) + IF (title LIKE '%мама%', 5.71, 0) + IF (title LIKE '%мыла%', 5.71, 0) + IF (title LIKE '%раму%', 5.71, 0)  + 
IF (description LIKE '%мама мыла раму%', 20, 0) + IF (description LIKE '%мама%', 2.86, 0) + IF (description LIKE '%мыла%', 2.86, 0) + IF (description LIKE '%раму%', 2.86, 0)  + 
IF (text LIKE '%мама мыла раму%', 10, 0) + IF (text LIKE '%мама%', 1.43, 0) + IF (text LIKE '%мыла%', 1.43, 0) + IF (text LIKE '%раму%', 1.43, 0) AS rel
FROM pages 
WHERE 
(title LIKE '%мама%' OR title LIKE '%мыла%' OR title LIKE '%раму%') OR
(description LIKE '%мама%' OR description LIKE '%мыла%' OR description LIKE '%раму%') OR
(text LIKE '%мама%' OR text LIKE '%мыла%' OR text LIKE '%раму%')
ORDER BY rel DESC

</code>
</pre>
<p>Вот такой немаленький запросик получился))) Теперь попробуем разобрать что значат все эти непонятные коэффициенты 5.71, 2.86 и 1.43. Для этого я нарисую маленькую табличку.</p>
<table border="1" align="center" style="border-collapse: collapse;">
<tr>
<th>\</th>
<th>Все</th>
<th>мама</th>
<th>мыла</th>
<th>раму</th>
</tr>
<tr>
<td>title</td>
<td>40</td>
<td>5.71</td>
<td>5.71</td>
<td>5.71</td>
</tr>
<tr>
<td>description</td>
<td>20</td>
<td>2.86</td>
<td>2.86</td>
<td>2.86</td>
</tr>
<tr>
<td>text</td>
<td>10</td>
<td>1.43</td>
<td>1.43</td>
<td>1.43</td>
</tr>
</table>
<p>Сумма первого столбика получается как раз 70%, сумма всех остальных ячеек 30% в результате искомые 100% релевантности. Сумма каждого следующего столбика 10%. А сумма каждой ячейки высчитывается по формуле (вес поля) * (общее число процентов 30) / (общее число коэффициентов 7) / (количество слов), если подставить поле title то выйдет 4*30/7/3 = 5.71. В общем, я думаю, поняли, кто не понял, возьмите калькулятор!</p>
<p>В том что такой запрос отрабатывает весьма шустро вы можете перейдя на страницу поиска, там выводиться время потраченное на запрос. </p>
<p>Кстати в моем поиске еще наложена логика отключения полей, если отключено одно поле то коэффициенты становятся 3 и 4 , а если отключено два поля то оставшееся имеет коэффициент 7. И еще не забудьте удалить пробелы в начале и конце строки, а также двойные пробелы в середине. Все!</p>]]></content:encoded>
			<wfw:commentRss>http://mabp.kiev.ua/2008/04/26/search_engine_works_now/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
