<?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>Работа для  программистов</title>
	<atom:link href="http://job-interview.ru/articles/feed" rel="self" type="application/rss+xml" />
	<link>http://job-interview.ru/articles</link>
	<description>вакансии, вопросы, статьи</description>
	<lastBuildDate>Thu, 29 Mar 2012 20:53:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Выделение областей изображения со схожими цветовыми характеристиками</title>
		<link>http://job-interview.ru/articles/post/362</link>
		<comments>http://job-interview.ru/articles/post/362#comments</comments>
		<pubDate>Thu, 29 Mar 2012 20:30:50 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Алгоритмы]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[MatLab]]></category>
		<category><![CDATA[изображения]]></category>

		<guid isPermaLink="false">/articles/?p=362</guid>
		<description><![CDATA[
Сегодня на рынке программных продуктов можно найти огромный выбор средств для обработки изображений. Есть и такие гиганты как Adobe Photoshop и просто любительские программы, написанные студентами для курсовых проектов. Поэтому выбор пользователя в этом плане велик. В этой статье я не буду обсуждать программные средства для обработки изображений, аналитических статей на этот счет предостаточно. Тут [...]]]></description>
			<content:encoded><![CDATA[<p>
Сегодня на рынке программных продуктов можно найти огромный выбор средств для <strong>обработки изображений</strong>. Есть и такие гиганты как <em>Adobe Photoshop</em> и просто любительские программы, написанные студентами для курсовых проектов. Поэтому выбор пользователя в этом плане велик. В этой статье я не буду обсуждать программные средства для обработки изображений, аналитических статей на этот счет предостаточно. Тут я хочу рассмотреть очень подробно лишь только один маленький пункт из огромного количества предложенных путей обработки изображений.
</p>
<p>
<strong>Обработка изображений</strong> сейчас модное направление в области разработки <em>программного обеспечения</em>. Начать обработку изображения можно уже на стадии фотографирования.  По поводу качества такой обработки сказать ничего не могу, но такие возможности фотоаппаратов, как <strong>обнаружение лица</strong> и других объектов вполне себе работают и причем неплохо. Другое дело – это <em>распознавание лиц</em>, тут пока технологии отстают. Мой ноутбук никак не хочет идентифицировать меня по лицу!
</p>
<p><span id="more-362"></span></p>
<p>
Основой  обработки изображения является выделение области изображения со схожими характеристиками, такое, как, например, выделение образов. Список <strong>алгоритмов</strong> для выделения образов или сегментов уже давно известен и обсуждается многими. Хотя, что значит обсуждается? Просто добавляется каждый раз новая статистика по работе алгоритмов на практике &#8211;  как работает, с какой точностью.
</p>
<p>
Когда я слышу о задаче выделения областей,  у меня сразу возникает несколько вопросов:
</p>
<blockquote><p>
&mdash; По какому критерию производить сравнение?<br />
&mdash; Как определить, что пиксели относятся к одной области?
</p></blockquote>
<p>
Начнем с первого пункта. Тут я постараюсь описать все довольно просто.
</p>
<p>
Все изображение состоит из маленьких частиц-пикселей. На сегодняшний день <strong>пиксель</strong> может быть представлен двумя способами – это с помощью <strong>RGB</strong> или <strong>YCrCb</strong>. Это так называемое представление цветного пространства пикселя. Между двумя этими представлениями существуют формулы перехода от одного пространства к другому. На мой взгляд, цветное пространство YCbCr используется только в формате кодирования <strong>JPEG</strong>, так как позволяет значительно уменьшить хранимую информацию о пикселях. При работе с <em>растровыми изображениями</em> для анализа чаще всего рассматривают формат представления RGB, хотя в последнее время к нему добавили еще одну компоненту – это так называемая &#8220;<em>яркость</em>&#8220;. Таким образом, для рассмотрения алгоритмов в этой статье я выбираю представление пикселей в RGB &#8211; пространстве, при необходимости может добавится еще одна, четвертая компонента.
</p>
<p>
Вопрос отнесения пикселей к одной области изображения представляет собой  интересную задачу. <strong>Алгоритм</strong>, который определяет отношение пикселя к заданной области, называется «<strong>Выращивание регионов, дробление-слияние</strong>».  Смысл метода в том, чтобы постепенно добавлять к определённой области пиксели, удовлетворяющие характеристикам области.
</p>
<p>
Для присоединения пикселя к области  существует несколько алгоритмов. Это и алгоритм &#8220;<strong>k-средних</strong>&#8220;, и &#8220;<strong>watershed</strong>&#8221; алгоритм. Смысл алгоритмов определить критерий, границу, по которой будет происходить отбор пикселей.
</p>
<p>
Для выбора этой границы произведем <strong>анализ изображения</strong>. Будем оценивать изображение по распределению пикселей и их значению. Наиболее популярный инструмент для разработки и анализа алгоритмов, на мой взгляд, это <strong>Matlab</strong>. В последних версиях Matlab появился <strong>ToolBox</strong> для обработки и анализа изображения. Тут реализованы почти все функции, которые необходимы для этого.
</p>
<p>
Одна из самых популярных функций в Matlab для анализа – это <strong>построение гистограмм</strong>. Тут надо заметить, что стандартная функция для считывания изображения в память – это <em>imread()</em>. Это функция на выходе формирует трехмерный массив пикселей, где число строк и столбцов равно ширине и высоте изображения соответственно. Итак, после применения этой функции получаем массивы пикселей в пространстве RGB.
</p>
<p>
Для построения гистограммы требуется одномерный массив, поэтому построим три гистограммы.
</p>
<p>
Наше изображение
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/1.png" align="center" border="0">
</p>
<p>
Для построения гистограмм изображений предусмотрен специальный инструмент <em>imhist</em>, который строит распределения пикселей по цветам (256 цветов).
</p>
<p>
Гистограммы по трем матрицам.
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/2.png" align="center" border="0">
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/3.png" align="center" border="0">
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/4.png" align="center" border="0">
</p>
<p>
Исходя из анализа гистограмм, сразу приходит идея о том, чтобы построить разделение на объекты при помощи разделения на цвета. То есть, тут можно отталкиваться от предположения, что, если, например, на значение пикселя в <strong>голубом канале</strong> приходится более 10000 пикселей, то эти пиксели, скорее всего, относятся к одной области. Для проверки были реализованы такие функции, которые показали следующий результат.
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/5.png" align="center" border="0">
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/6.png" align="center" border="0">
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/7.png" align="center" border="0">
</p>
<p>
Эти результаты были получены, если принять гипотезу о том, что одинаковые пиксели соответствуют одной области.
</p>
<p>
Здесь мы постарались выделить области пикселей, которых наибольшее  количество в канале, далее можно использовать <em>рекуррентную функцию</em> для выделения подобных областей до тех пор, пока изображение не будет разбито на области по значению пикселей.
</p>
<p>
Для получения данного результата был применен следующий цикл.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="matlab" style="font-family:monospace;"><span style="color: #0000FF;">for</span> <span style="color: #33f;">i</span>=<span style="color: #33f;">1</span>:<span style="color: #33f;">1</span>:x
  <span style="color: #0000FF;">for</span> <span style="color: #33f;">j</span>=<span style="color: #33f;">1</span>:<span style="color: #33f;">1</span>:y
    <span style="color: #0000FF;">if</span><span style="color: #080;">&#40;</span><span style="color: #0000FF;">abs</span><span style="color: #080;">&#40;</span> fgrey<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>,<span style="color: #33f;">j</span><span style="color: #080;">&#41;</span>-position <span style="color: #080;">&#41;</span> &lt; <span style="color: #33f;">2</span><span style="color: #080;">&#41;</span>
      fgrey<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>,<span style="color: #33f;">j</span><span style="color: #080;">&#41;</span>=t;
      count=count+<span style="color: #33f;">1</span>;
    <span style="color: #0000FF;">end</span>
  <span style="color: #0000FF;">end</span>
<span style="color: #0000FF;">end</span></pre></div></div>

</p>
<p>
Здесь position &#8211; это значение пикселей, по которым происходит выборка областей. В этом выражении принимается поправка, что отклонение от выбранного значения может составлять 2 пункта.
</p>
<p>
Метод простой и легко реализуемый, хотя, конечно, он далек от совершенства. Вот тут я могу предложить небольшую модификацию метода, которая будет рассмотрена ниже.
</p>
<p>
В основе модификации лежит предположение о том, что значения пикселей в одной области или сегменте меняются постепенно, то есть осуществляется плавный переход. Например, в нашем изображении цвет неба плавно меняется от темного голубого к голубому. Этот метод больше похож на <strong>метод наращивания областей</strong>.
</p>
<p>
Рассмотрим тут его упрощенный вариант.
</p>
<p>
Будем рассматривать массив пикселей из трех подряд идущих значений. В нашем случае возьмем три пикселя. Найдем их среднее значение.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="matlab" style="font-family:monospace;">среднее=<span style="color: #080;">&#40;</span>f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>-<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>+f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>+f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>+<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span><span style="color: #080;">&#41;</span>/<span style="color: #33f;">3</span>;</pre></div></div>

</p>
<p>
Это значение примем за основу. Далее будем наращивать области, также используя три подряд идущих пикселя. Если разница значений удовлетворяет заданному критерию, то мы присоединяем эту область к исходной области, если нет, отбрасываем. Для трех матриц получаем следующий результат.
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/8.png" align="center" border="0">
</p>
<p>
То есть мы видим, что изображение распадается на области с одинаковыми цветовыми значениями.
</p>
<p>
Функция для нахождения среднего по трем пикселям.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="matlab" style="font-family:monospace;"><span style="color: #0000FF;">for</span> z=<span style="color: #33f;">1</span>:<span style="color: #33f;">1</span>:<span style="color: #33f;">3</span>
  <span style="color: #0000FF;">for</span> <span style="color: #33f;">i</span>=<span style="color: #33f;">2</span>:<span style="color: #33f;">3</span>:x-<span style="color: #33f;">1</span>
    <span style="color: #0000FF;">for</span> <span style="color: #33f;">j</span>=<span style="color: #33f;">1</span>:<span style="color: #33f;">1</span>:y 
      dev=<span style="color: #080;">&#40;</span>f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>-<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>+f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>+f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>+<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span><span style="color: #080;">&#41;</span>/<span style="color: #33f;">3</span>;
      <span style="color: #0000FF;">if</span><span style="color: #080;">&#40;</span>dev~=<span style="color: #33f;">0</span><span style="color: #080;">&#41;</span>
	<span style="color: #0000FF;">break</span>;
      <span style="color: #0000FF;">end</span>
    <span style="color: #0000FF;">end</span>
  <span style="color: #0000FF;">end</span>
<span style="color: #0000FF;">end</span></pre></div></div>

</p>
<p>
Функция для выделения областей.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="matlab" style="font-family:monospace;"><span style="color: #0000FF;">for</span> z=<span style="color: #33f;">1</span>:<span style="color: #33f;">1</span>:<span style="color: #33f;">3</span>
  <span style="color: #0000FF;">for</span> <span style="color: #33f;">i</span>=<span style="color: #33f;">2</span>:<span style="color: #33f;">3</span>:x-<span style="color: #33f;">1</span>
    <span style="color: #0000FF;">for</span> <span style="color: #33f;">j</span>=<span style="color: #33f;">1</span>:<span style="color: #33f;">1</span>:y
      devnew=<span style="color: #080;">&#40;</span>f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>-<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>+f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>+f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>+<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span><span style="color: #080;">&#41;</span>/<span style="color: #33f;">3</span>;
      <span style="color: #0000FF;">if</span><span style="color: #080;">&#40;</span><span style="color: #080;">&#40;</span>dev-devnew<span style="color: #080;">&#41;</span>&lt;<span style="color: #33f;">0.1</span><span style="color: #080;">&#41;</span>
	dev=devnew;
	f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>-<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>=<span style="color: #33f;">0</span>;
	f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>=<span style="color: #33f;">0</span>;
	f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>+<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>=<span style="color: #33f;">0</span>;
      <span style="color: #0000FF;">end</span>
    <span style="color: #0000FF;">end</span>
  <span style="color: #0000FF;">end</span>
<span style="color: #0000FF;">end</span></pre></div></div>

</p>
<p>
Погрешность для трех пикселей принята равным 0.1, данный параметр можно изменить, но для этого изображения параметр 0.1 является наилучшим.
</p>
<p>
Таким образом, после применения всех фильтров мы получаем следующее изображение.
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/9.png" align="center" border="0">
</p>
<p>
Визуальная оценка показывает, что выделение области вторым методом, дает более плавные переходы из одной области в другую.
</p>
<p>
Дальнейшее улучшение результатов даст возможность выделить области. Для этого надо использовать метод выделения пограничных контуров.
</p>
<p>
Тут можно использовать алгоритм выращивания областей от точки. Выбирая точку в пространстве пикселей, если она удовлетворяет заданному значению, мы присоединяем точку, если нет, пропускаем. Похоже на второй алгоритм, но тут идет привязка только по связным областям.
</p>
<p>
Например, выбирается точка из заданной области point(i,j), далее ищется точка со схожими значения в окружающем пространстве.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="matlab" style="font-family:monospace;"><span style="color: #0000FF;">for</span> <span style="color: #33f;">j</span>=point_j:<span style="color: #33f;">1</span>:y
  <span style="color: #0000FF;">if</span><span style="color: #080;">&#40;</span>F<span style="color: #080;">&#40;</span>point_i,<span style="color: #33f;">j</span><span style="color: #080;">&#41;</span>~=<span style="color: #33f;">0</span><span style="color: #080;">&#41;</span>
    <span style="color: #080;">&#91;</span>point_i,<span style="color: #33f;">j</span><span style="color: #080;">&#93;</span>=Point<span style="color: #080;">&#40;</span>F,point_i-<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span><span style="color: #080;">&#41;</span>;
  <span style="color: #0000FF;">else</span>
    <span style="color: #0000FF;">for</span> z=<span style="color: #33f;">1</span>:<span style="color: #33f;">1</span>:<span style="color: #33f;">3</span>
      f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>-<span style="color: #33f;">2</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>=<span style="color: #33f;">0</span>;
      f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>-<span style="color: #33f;">1</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>=<span style="color: #33f;">0</span>;
      f<span style="color: #080;">&#40;</span><span style="color: #33f;">i</span>,<span style="color: #33f;">j</span>,z<span style="color: #080;">&#41;</span>=<span style="color: #33f;">0</span>;
    <span style="color: #0000FF;">end</span>
  <span style="color: #0000FF;">end</span>
<span style="color: #0000FF;">end</span></pre></div></div>

</p>
<p>
Здесь рассмотрение стоящих рядом точек идет только в одном направлении, сдвигаясь вправо по столбам.
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/10.png" align="center" border="0">
</p>
<p>
Применение этого метода к уже частично обработанному изображению приближает нас к цели. Конечно, тут не получен идеальный вариант, но был рассмотрен <em>математический аппарат</em> для выделения областей со схожими характеристиками пикселей.
</p>
<p>
Следующим улучшением может быть создание более <em>интеллектуальной системы</em>, которая на основании некоторых изображений создает базу коэффициентов для отбора пикселей. Такие системы называются обучающимися.
</p>
<p>
Теперь рассмотрим реализацию этого примера на <em>языках программирования высокого уровня</em>.
</p>
<p>
В <em>.NET</em> существует класс Bitmap. Данный класс предоставляет большие возможности для <strong>обработки изображений</strong>.
</p>
<p>
Данный класс, также как и <strong>Matlab</strong>, представляет изображение в виде массива пикселей. Есть лишь одно отличие &#8211; вместо размерности матрицы три, в классе <strong>Bitmap</strong> представляется изображение в виде матрицы размерностью четыре.
</p>
<p>
Применим ту же фильтрацию, что и для Matlab, сделав только одно усовершенствование. Построим для каждого цвета что-то вроде <strong>гистограммы</strong>, но только будем объединять рядом стоящие значения пикселей. В нашем случае расстояние между схожими пикселями будет равно 4.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> FindMean<span style="color: #000000;">&#40;</span>BitmapIm, intlength, charcanal<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
  <span style="color: #FF0000;">int</span> middlepixel <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
  middlepixel<span style="color: #008000;">=</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">460</span>,<span style="color: #FF0000;">256</span><span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">G</span><span style="color: #008000;">;</span>
  <span style="color: #FF0000;">int</span> count <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
  <span style="color: #FF0000;">int</span> countofcolor<span style="color: #008000;">=</span><span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
  countofcolor<span style="color: #008000;">=</span>Math.<span style="color: #0000FF;">Abs</span><span style="color: #000000;">&#40;</span><span style="color: #FF0000;">256</span><span style="color: #008000;">/</span>length<span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
  mas_color<span style="color: #008000;">=</span><span style="color: #008000;">new</span> <span style="color: #FF0000;">int</span><span style="color: #000000;">&#91;</span>countofcolor<span style="color: #000000;">&#93;</span><span style="color: #008000;">;</span>
&nbsp;
  <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>countofcolor<span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
    mas_color<span style="color: #000000;">&#91;</span>i<span style="color: #000000;">&#93;</span> <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
&nbsp;
  <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>canal<span style="color: #008000;">==</span><span style="color: #666666;">'B'</span><span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> j <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> j <span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> j<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
	<span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i,j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">B</span><span style="color: #008000;">!=</span>Color.<span style="color: #0000FF;">Black</span>.<span style="color: #0000FF;">B</span><span style="color: #000000;">&#41;</span>
        <span style="color: #000000;">&#123;</span>
	  mas_color<span style="color: #000000;">&#91;</span>Math.<span style="color: #0000FF;">Abs</span><span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">B</span> <span style="color: #008000;">/</span> length<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><span style="color: #008000;">++;</span>
	  count<span style="color: #008000;">++;</span>
	<span style="color: #000000;">&#125;</span>
  <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>canal <span style="color: #008000;">==</span> <span style="color: #666666;">'G'</span><span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> j <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> j <span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> j<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
	<span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">G</span> <span style="color: #008000;">!=</span> Color.<span style="color: #0000FF;">Black</span>.<span style="color: #0000FF;">G</span><span style="color: #000000;">&#41;</span>
	<span style="color: #000000;">&#123;</span>
	  mas_color<span style="color: #000000;">&#91;</span>Math.<span style="color: #0000FF;">Abs</span><span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">G</span> <span style="color: #008000;">/</span> length<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><span style="color: #008000;">++;</span>
	  count<span style="color: #008000;">++;</span>
	<span style="color: #000000;">&#125;</span>
  <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>canal <span style="color: #008000;">==</span> <span style="color: #666666;">'R'</span><span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> j <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> j <span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> j<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
	<span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">R</span> <span style="color: #008000;">!=</span> Color.<span style="color: #0000FF;">Black</span>.<span style="color: #0000FF;">R</span><span style="color: #000000;">&#41;</span>
	<span style="color: #000000;">&#123;</span>
	  mas_color<span style="color: #000000;">&#91;</span>Math.<span style="color: #0000FF;">Abs</span><span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">R</span> <span style="color: #008000;">/</span> length<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><span style="color: #008000;">++;</span>
	  count<span style="color: #008000;">++;</span>
	<span style="color: #000000;">&#125;</span>
  <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>canal <span style="color: #008000;">==</span> <span style="color: #666666;">'A'</span><span style="color: #000000;">&#41;</span>
  <span style="color: #000000;">&#123;</span>
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> j <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> j <span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> j<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
	<span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">A</span> <span style="color: #008000;">!=</span> Color.<span style="color: #0000FF;">Black</span>.<span style="color: #0000FF;">A</span><span style="color: #000000;">&#41;</span>
	<span style="color: #000000;">&#123;</span>
	  mas_color<span style="color: #000000;">&#91;</span>Math.<span style="color: #0000FF;">Abs</span><span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">A</span> <span style="color: #008000;">/</span> length<span style="color: #000000;">&#41;</span><span style="color: #000000;">&#93;</span><span style="color: #008000;">++;</span>
	  count<span style="color: #008000;">++;</span>
	<span style="color: #000000;">&#125;</span>
  <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

</p>
<p>
Здесь происходит распределение значений пикселей по цветовым компонентам. А именно, пиксели с близко стоящими значениями объединяются в группу. Расстояние между такими группами в нашем примере равно 4. В дальнейшем, благодаря этому массиву, можно выделять значения пикселей, которых в изображении большинство.
</p>
<p>
При помощи разделения каналов было установлено, что наилучший результат получается при выделение областей из голубого канала, наихудший результат получен при выделении из зеленого.
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/11.png" align="center" border="0">
</p>
<p>
Как видно, выделилась область голубого неба.
</p>
<p>
С помощью наложения некоторых фильтров, сначала голубого, а потом красного, получается следующее изображение.
</p>
<p>
<img src="http://job-interview.ru/img/segmentation/12.png" align="center" border="0">
</p>
<p>
Пример кода, для обработки голубого канала.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="csharp" style="font-family:monospace;"><span style="color: #0600FF;">public</span> <span style="color: #0600FF;">void</span> MarkBlue<span style="color: #000000;">&#40;</span>BitmapIm<span style="color: #000000;">&#41;</span>
<span style="color: #000000;">&#123;</span>
  <span style="color: #FF0000;">int</span> metka <span style="color: #008000;">=</span> <span style="color: #008000;">-</span><span style="color: #FF0000;">1</span>, count <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span>, count_opposite <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
  <span style="color: #008080; font-style: italic;">// Color pixel = MarkIm.GetPixel(0, 0);</span>
  <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> j <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> j <span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> j<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span> <span style="color: #008000;">==</span> Color.<span style="color: #0000FF;">Black</span><span style="color: #000000;">&#41;</span>
	<span style="color: #008080; font-style: italic;">//    count++;</span>
&nbsp;
  count <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
  FindMean<span style="color: #000000;">&#40;</span>Im, <span style="color: #FF0000;">4</span>,<span style="color: #666666;">'B'</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
  <span style="color: #FF0000;">int</span> maxColor <span style="color: #008000;">=</span> mas_color<span style="color: #000000;">&#91;</span><span style="color: #FF0000;">0</span><span style="color: #000000;">&#93;</span><span style="color: #008000;">;</span>
  <span style="color: #FF0000;">int</span> maxIndex <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span>
  <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">1</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span> <span style="color: #FF0000;">256</span> <span style="color: #008000;">/</span> <span style="color: #FF0000;">4</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
    <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>maxColor<span style="color: #008000;">&lt;</span>mas_color<span style="color: #000000;">&#91;</span>i<span style="color: #000000;">&#93;</span><span style="color: #000000;">&#41;</span>
    <span style="color: #000000;">&#123;</span>
      maxColor <span style="color: #008000;">=</span> mas_color<span style="color: #000000;">&#91;</span>i<span style="color: #000000;">&#93;</span><span style="color: #008000;">;</span>
      maxIndex <span style="color: #008000;">=</span> i<span style="color: #008000;">;</span>
    <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #008080; font-style: italic;">//  MessageBox.Show(Convert.ToString(mas_color[20]));</span>
  <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> j <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> j <span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> j<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>maxIndex<span style="color: #008000;">&gt;</span> <span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span>.<span style="color: #0000FF;">B</span><span style="color: #000000;">&#41;</span> <span style="color: #008000;">/</span> <span style="color: #FF0000;">4</span><span style="color: #000000;">&#41;</span>
      <span style="color: #000000;">&#123;</span>
	<span style="color: #008080; font-style: italic;">//  count++;</span>
	Im.<span style="color: #0000FF;">SetPixel</span><span style="color: #000000;">&#40;</span>i, j, Color.<span style="color: #0000FF;">Black</span><span style="color: #000000;">&#41;</span><span style="color: #008000;">;</span>
      <span style="color: #000000;">&#125;</span>
&nbsp;
  <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> i <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> i<span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Width</span><span style="color: #008000;">;</span> i<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
    <span style="color: #0600FF;">for</span> <span style="color: #000000;">&#40;</span><span style="color: #FF0000;">int</span> j <span style="color: #008000;">=</span> <span style="color: #FF0000;">0</span><span style="color: #008000;">;</span> j <span style="color: #008000;">&lt;</span>Im.<span style="color: #0000FF;">Height</span><span style="color: #008000;">;</span> j<span style="color: #008000;">++</span><span style="color: #000000;">&#41;</span>
      <span style="color: #0600FF;">if</span> <span style="color: #000000;">&#40;</span>Im.<span style="color: #0000FF;">GetPixel</span><span style="color: #000000;">&#40;</span>i, j<span style="color: #000000;">&#41;</span> <span style="color: #008000;">==</span> Color.<span style="color: #0000FF;">Black</span><span style="color: #000000;">&#41;</span>
	count<span style="color: #008000;">++;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

</p>
<p>
Фактически, мы получили простой математический аппарат для выделения областей. Тут за основу принимается распределение пикселей по значению, геометрические и пространственные характеристики никак не учитываются.
</p>
<p>
В дальнейшем после применения фильтров для цвета пикселей, на мой взгляд, должен быть поставлен вопрос о правильном выделении пограничных контуров. Тут может возникнуть проблема, которая отображена на изображениях, приведенных выше. Что, если область принадлежит области &#8220;лошади&#8221;, но при этом цветовые характеристики совпадают с областью &#8220;неба&#8221;?
</p>
<p>
Думаю, для решения этой проблемы потребуется визуальная оценка результатов, сделанная человеком.
</p>
<p>
В общем, метод разбиения областей с помощью цветовых характеристик имеет много недостатков и в голом виде не может претендовать на законченность, однако, совершенствование и добавление новых путей решения в итоге приведет к хорошему результату.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/362/feed</wfw:commentRss>
		<slash:comments>22057</slash:comments>
		</item>
		<item>
		<title>Разработка в среде WEB: Java или PHP?</title>
		<link>http://job-interview.ru/articles/post/356</link>
		<comments>http://job-interview.ru/articles/post/356#comments</comments>
		<pubDate>Tue, 28 Feb 2012 18:31:26 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[ООП]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">/articles/?p=356</guid>
		<description><![CDATA[Вместо предисловия.
Я постараюсь максимально объективно сравнить два языка. В конечном итоге, выбор платформы, стиля и языка &#8211; не определяющий фактор успеха. Главное, чтобы руки разработчика не повторяли форму интеграла. Ведь язык лишь инструмент, а инструмент, как известно, продолжение рук. 

Начнем.


WEB развивается уже второй десяток лет. Время статичных HTML-страниц кануло в истории, на смену которому пришел [...]]]></description>
			<content:encoded><![CDATA[<h2>Вместо предисловия.</h2>
<p>Я постараюсь максимально объективно сравнить два языка. В конечном итоге, выбор платформы, стиля и языка &#8211; не определяющий фактор успеха. Главное, чтобы руки разработчика не повторяли форму <em>интеграла</em>. Ведь язык лишь инструмент, а инструмент, как известно, продолжение рук. </p>
<p><span id="more-356"></span></p>
<h2>Начнем.</h2>
<p><img border="0" align="left" style="padding: 0px 10px 10px;" src="/img/javaphp/javaphp.jpg"></p>
<p style="height: 110px;">
<strong>WEB</strong> развивается уже второй десяток лет. Время статичных <strong>HTML-страниц</strong> кануло в истории, на смену которому пришел абстрактный стандарт <em>WEB2</em>, главное требование которого &#8211; взаимодействие с пользователем. Спорить, правильно ли это, конечно, можно, только в таком случае появляется вполне резонный вопрос: зачем читать эту статью, если она о средствах создания подобных сервисов? </p>
<h2>Порог вхождения.</h2>
<p>Традиционно для сравнительного анализа языков в первую очередь используют удобство синтаксиса, скорость работы и возможности.</p>
<p>Такой подход логичен для выбора собственного. А вот с точки зрения работодателя, качества самого программиста значительно важнее.</p>
<p><strong>PHP</strong> считается простым языком. Это не удивительно: от открытия учебника до первого &#8220;HelloWorld-a&#8221; проходит не больше 5 минут. С одной стороны это хорошо. Но подводных камней не мало.</p>
<p><img border="0" align="left" src="/img/javaphp/helloworld.jpg" style="padding: 10px;"></p>
<p>Потратив неделю на изучение PHP, можно научиться базовым приемам ввода-вывода, примитивной <em>выборке из БД</em> и парочке других алгоритмов обработки информации. С усложнением задач появляется соблазн <em>изобретать &#8220;велосипеды&#8221;</em> и &#8220;костыли&#8221; на основе старых знаний, делая код нечитабельным, уничтожая возможность дальнейшей поддержки на корню.</p>
<p>Работа с таким &#8220;<em>кодером</em>&#8221; в команде, или еще хуже, поддержка проекта, написанного им, превращается в будни школьного учителя. Естественно, это утверждение относится не ко всем, но такая проблема существует.</p>
<p>Что касается <strong>Java</strong>, порог вхождения очень высокий. Вместо &#8220;<em>Установка LAMP под Ubuntu</em>&#8221; и &#8220;<em>Скачать самоучитель PHP</em>&#8220;, необходимо вникнуть в <strong>сервлеты</strong>, взаимодействие между ними, <strong>jsp</strong>, научиться работе с каким-нибудь <em>фреймворком</em>.</p>
<p>Плюс <strong>ООП</strong>, который в Java обязателен. Если проводить аналогию, начало работы сравнимо с <em>высшей математикой</em> в ВУЗ-е: всех неспособных отправить на службу родине.</p>
<p>Подобный подход к оценке языка не панацея. Достаточно много серьезных проектов, написанных на <strong>PHP</strong>. Более того, на данный момент в сфере <strong>WEB-разработок</strong> он доминирует.</p>
<h2>Синтаксис и код.</h2>
<p><img border="0" align="left" src="/img/javaphp/sourcecode.jpg" style="padding: 10px;"></p>
<p>Одна из обсуждаемых проблем <strong>Java</strong> &#8211; длиннейшие названия классов и стандартных методов. Чего только стоит &#8220;<em>System.out.println()</em>&#8221; оного вместо &#8220;<em>echo</em>&#8221; на PHP. Конечно, это легко решается &#8220;<em>import</em>-ом&#8221; в начале документа или выбором современной <em>IDE</em>, в которой достаточно написать первую букву метода или поля, как появится возможность выбора нужного из списка. Тем не менее, отрицать впечатляющий объем кода на Java &#8211;  предвзято.</p>
<p><strong>PHP</strong> тоже не идеален. Взять к примеру обязательный знак доллара перед переменной. Конечно, рациональное зерно различия между обозначениями переменных и методами(функциями) присутствует. Лично у меня это вызывает жуткую головную боль. В первую очередь от созерцания самого знака. Плюс, я так и не сумел привить у себя<br />
привычки ставить доллар перед каждой переменной. Слишком меркантильно, что-ли&#8230;</p>
<p>Что касается кода, я думаю мало кто станет спорить, что серьезный проект == серьезная <em>работа в команде</em>. А работа в команде требует годного, понятного кода, качественную <em>документацию</em>, и возможность эффективно распределить работу.</p>
<p>Здесь принудительное ООП Java и <strong>Javadoc</strong> для документации дают ощутимый прирост в копилке аргументов &#8220;За Java&#8221;.</p>
<p>В PHP эти возможности так же есть. Сравнительно недавно я узнал о аналогах Javadoc в PHP- <strong>phpdoc</strong>/<strong>PhpDocumentor</strong>.</p>
<p>С известных версий PHP поддерживает объектный подход(ООП). Правда он смешанный, и соблазн написать простую функцию без обертки очень большой.</p>
<h2>Техническая площадка.</h2>
<p><img border="0" align="left" src="/img/javaphp/servers.jpg" style="padding: 10px;"></p>
<p>С кодом мы разобрались. А вот что касается хостинга, Java в проигрыше. <strong>PHP-хостинг</strong> распространен и он дешевле.</p>
<p>Правда под вопросом, стоит ли экономить на хостинге, если проект серьезный? Тем не менее, то, что заменить техническую основу проекта на PHP проще &#8211; факт.</p>
<p>Другой вопрос, если проект используется в интрасети. Стоимость <strong>хостинга</strong> отпадает. И программирование на стороне клиента дает плюс в сторону Java. Интеграция <em>апплетов</em> на нем в сети интернет потерпела крах, так как для запуска они требуют имплементатор на локалхосте. Но когда клиенты доступны физически, проблем нет.</p>
<p>Единая платформа, без связки разных языков &#8211; очевидный плюс. </p>
<h2>Вместо заключения.</h2>
<p>Я постарался не затрагивать сравнения технических характеристик языков. Такой информации в интернете полно. Так же считаю, что качество разработки значительно важнее. Язык создан для человека, а не для процессора. Для второго есть ассемблер.</p>
<p>Претензий на объективность у меня нет. Я попытался, насколько успешно- не знаю. Буду рад аргументированной критике.</p>
<p>Под конец повторюсь: все в руках разработчика, язык лишь инструмент. Профессионал и пальцем болт закрутит.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/356/feed</wfw:commentRss>
		<slash:comments>509</slash:comments>
		</item>
		<item>
		<title>Программист на фрилансе</title>
		<link>http://job-interview.ru/articles/post/332</link>
		<comments>http://job-interview.ru/articles/post/332#comments</comments>
		<pubDate>Tue, 31 May 2011 19:51:38 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Фриланс]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[фриланс-биржи]]></category>

		<guid isPermaLink="false">/articles/?p=332</guid>
		<description><![CDATA[

В этой статье я хочу описать свой опыт работы на фрилансе.

Что за фриланс?

Может быть есть люди, которые не знают, что такое фриланс? &#8220;Freelance&#8221; буквально переводится как &#8220;внештатно&#8221;, соответственно &#8220;freelancer&#8221; — &#8220;внештатный сотрудник&#8221;. Обычно это подразумевает поиск заказов через интернет, выполнение их дома за компьютером (хотя некоторые ловко трудятся во время основной работы   ) [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/img/fl_sait_1000_rub.jpg" style="float:left;margin-right:5px;width:260px;" title="Сделаю сайт за 1000 рублей" /></p>
<p>
В этой статье я хочу описать свой опыт работы на фрилансе.
</p>
<h3>Что за фриланс?</h3>
<p>
Может быть есть люди, которые не знают, что такое <b>фриланс</b>? <i>&#8220;Freelance&#8221;</i> буквально переводится как &#8220;внештатно&#8221;, соответственно <i>&#8220;freelancer&#8221;</i> — &#8220;внештатный сотрудник&#8221;. Обычно это подразумевает поиск заказов через интернет, выполнение их дома за компьютером (хотя некоторые ловко трудятся во время основной работы <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ) и оплату выполненной работы через интернет. Существуют специальные сайты — фриланс-биржы — на которых происходит общение заказчиков, имеющих какие-либо задания, и исполнителей, готовых эти задания выполнить.
</p>
<p><span id="more-332"></span></p>
<h3>А зачем это нужно?</h3>
<p>
Наверное каждый программист замечал, что работая постоянно, у него не хватает времени заниматься какими-то своими проектами. А различные идеи периодически приходят, и думаешь: &#8220;Вот было бы время, обязательно бы это реализовал&#8221;. Да и на работе бывают времена, что приходится заниматься неинтересными делами. Тем более в мои планы не входило всю жизнь работать &#8220;на дядю&#8221;, рано или поздно пришлось бы уходить на вольные хлеба, и во время особо скучного периода на тогдашней постоянной работе я и решил это сделать.
</p>
<p>
Для начала я решил закрепиться на <b>фриланс-биржах</b>, чтобы в случае чего всегда можно было бы заработать денег, невзирая на текущую жизненную ситуацию, был бы под рукой ноутбук и интернет. К тому же всегда есть из чего выбрать: захотел делать сайт — вперед, захотел написать скрипт — флаг в руки, надоел язык программирования — меняй, никто не запрещает.
</p>
<h3>Биржи? Биржи. Биржи&#8230;</h3>
<p>
Фриланс-бирж существует множество, как российских, так и зарубежных, в итоге я зарегистрировался на трех — <i>freelancer.com</i>, <i>free-lance.ru</i> и <i>weblancer.net</i>.
</p>
<p><img src="/img/fl_ows_f.png" style="float:left;width:200px;margin-right:3px;" /></p>
<p>
freelancer.com я выбрал, так как прочитал довольно интересную статью, описывающую прелесть работы на ней. Здесь я решил представиться веб-студией, по идее такой подход вызывает больше доверия у заказчиков, придумал &#8220;конторе&#8221; название, сделал простенький логотип, зарегистрировался и начал осматриваться.<br />
Если описать в общем, сайт представляет собой типичную фриланс-биржу &#8211; страницы разделов по возможным IT-работам, например создание сайтов &#8220;под ключ&#8221;, создание дизайнов, работа с различными CMS, написание скриптов, системное администрирование и т.д. Заказчик выбирает нужный ему раздел, создает проект, на который откликаются заинтересовавшиеся фрилансеры.
</p>
<p>
На freelancer.com ищут заказы очень много фрилансеров, среди которых немало выходцев из Азии. Качество работы большинства этих товарищей, как и знание английского языка, оставляет желать лучшего (кто не слышал про программистов-индусов <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  ), но они берут ценами, иногда демпинг с их стороны вызывает даже не недоумение, а смех. Вполне реально найти &#8220;исполнителя&#8221; на сложный специфичный портал за сумму например 100$ и сроком исполнения 3 дня. И это предложение еще могут перебить!<br />
Естественно, есть и мастера своего дела, с высочайшим профессионализмом, большим опытом и умением подойти к клиенту.
</p>
<p>
К сожалению, на этом сайте мне так и не удалось получить ни одного заказа, наверное из-за окончательной переориентации на отечественный рынок. Свою роль сыграли и не очень удовлетворительный английский, и разница во времени с многими заказчиками.
</p>
<p>
Российские биржи, на которых я зарегистрировался — free-lance.ru и weblancer.net. free-lance.ru &#8211; самая известная из отечественных, держит первенство по количеству проектов и активных фрилансеров. Содержит много платных услуг, жизнь без которых затруднена, например не имея pro-аккаунта можно подавать только три заявки на понравившиеся проекты в сутки. Но таким ограничением страдают все биржи, которые я встречал. Впрочем это мне не очень мешало, с первых дней мне хотелось насладится преимуществом выбора интересных заданий. К сожалению, появлялись они не так часто, как хотелось бы, а при подаче заявки меня всегда обходили более опытные исполнители, с отзывами и более долгим временем нахождения на сайте.
</p>
<p><a href="/img/fl_dem_cust.jpg" target="_blank"><img src="/img/fl_dem_cust_sm.jpg" style="float:left;margin-right:5px;" /></a></p>
<p>
Про это стоит упомянуть подробнее. Практически все заказчики смотрят на количество отзывов, имеющихся у фрилансера, которые оставили прошлые работодатели. Хорошо выполнил работу — написали положительный, плохо, не выполнил или исчез — отритцательный. Наверное уже с 3-мя отритцательными отзывами лучше завести новый аккаунт, так же как и если первый отзыв — негативный. То же самое и с временем, прошедшим после регистрации, некоторые не доверяют людям, у которых оно меньше месяца. Сначала порой приходилось работать и <del>за еду</del> просто за отзыв.
</p>
<p>
Когда подходящий проект найден, встает задача, чтобы заказчик выбрал именно вас. Тут у каждого свой подход, кто-то просто называет цену и оставляет сообщение &#8220;пишите в личку&#8221;, кто-то строчит простыни текста, в подробностях расписывая все свои предыдущие достижения, кто-то выбирает нечто среднее. По-моему стоит писать, какие подобные задания уже приходилось выполнять и по-возможности дать понять, что понимаешь задание и чуть ли не начал его делать.
</p>
<p>
Но вот первый проект получен, наконец-то меня выбрали исполнителем! Обсудив все детали задания, пора начинать работать! Но, что все не так просто, стало понятно через пару проектов. ТЗ и детали нужно обговаривать ОЧЕНЬ подробно, выясняя все до последних мелочей, иначе дорабатывать и изменять казалось бы незначительные и неважные детали и наводить красоту по вкусу заказчика можно вечно, либо, неправильно поняв суть задания, вообще выбрать неверный путь решения задачи. Был случай, когда недели две работы потратились впустую из-за непонимания и несогласованности между мной и заказчиком, в итоге я потерял деньги, а клиент время, хорошо, что в результате разошлись мирно, без написания отритцательных отзывов друг другу.
</p>
<p>
И наконец, самый приятный момент — оплата. На всех биржах есть сервисы безопасных сделок, которые сделаны для того, чтобы ни работодатель, ни исполнитель не обманывали друг друга. Я ими не пользовался ни разу, предпочитая или доверять заказчику, получая деньги после выполнения задания, или беря предоплату. В подавляющем большинстве случаев оплата происходит с помощью вебмани или яндекс-денег.
</p>
<h3>Не биржей единой</h3>
<p>
Поиск заказов не ограничивается только биржами.<br />
У многих заказчиков постоянно появляются новые задания, и если ты хорошо выполнил одно, наверняка следующее также достанется тебе, плюс этот заказчик будет рекомендовать тебя своим знакомым, у которых возникла необходимость в привлечении стороннего сотрудника.<br />
Постепенно знакомые и бывшие коллеги узнают о твоей работе на фрилансе и заказы начинают приходить через них.<br />
Через некоторое время я перестал заходить на биржи и выполнял только подобные задания, потому что они скорее всего будут интересные, с заказчиком уже сложились более-менее неплохие отношения, почти нет недоверия и настороженности, как у тебя, что прокатят с деньгами, так и у него, что работа не будет выполнена.
</p>
<p>
Также не стоит забывать про свои задумки, отводить какое-то время на них, даже если пока ни одна из них еще не приносит какой-либо ощутимой отдачи, ведь это только пока <img src='/articles/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Главное, что для них находится время.
</p>
<h3>Ожидания и реальность</h3>
<p><img src="/img/fl_good_bad.jpg" /></p>
<p>
Для кого-то работать дома в кайф, но я знал, что постоянно находиться в четырех стенах мне будет затруднительно, однако утешал себя мыслью, что можно будет выйти, например, в парк и работать там. Но на практике зарядки ноутбука хватает не намного времени, у нетбука маленький экран, а на лавке в парке с этими девайсами неудобно сидеть. Если еще вспомнить, каким жарким было лето 2010, то можно понять, как я завидовал людям, сидящим в прохладных офисах с кондиционерами, тогда как дома был только плохо спасающий от этого ада вентилятор.
</p>
<p>
Когда я начинал свой путь по дороге фриланса, то не строил иллюзий, что в первый же день клиенты выстроятся в очередь, но все же было неожиданно, что уцепиться за первый проект удалось только недели через две. Эта ситуация получилась и из-за того, что, как упоминалось ранее, я не откликался на неинтересные заявки, а ждал чего-то более привлекательного. Зато проект оказался интересным, довольно денежным и с хорошим заказчиком, которому впоследствии я выполнил еще несколько заданий.
</p>
<p>
По поводу рабочего времени происходило примерно так, как я и думал: то работы нет, то работать приходится по ночам, не говоря уже про выходные. Если на постоянной работе знаешь, что в субботу-воскресенье отдыхаешь, на фрилансе все смешивается и иногда удивляешься радости друзей о том, что завтра выходной.<br />
Можно безболезненно с утра покататься на велосипеде, посреди рабочего дня прерваться, например, на гантели или прогулку (это если нет срочной работы, конечно <img src='/articles/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' />  ).
</p>
<p>
Волнующий денежный вопрос. Честно говоря, когда я уходил на фриланс, то ожидал, что буду зарабатывать больше. Очень сложно назвать среднюю сумму заработка, в первые месяцы у меня выходило не более 10-15 тысяч ежемесячно.
</p>
<h3>Итого</h3>
<p>
Что же в итоге? Не жалею ли я о том, что ушел с постоянной работы на фриланс? Нет.<br />
Сейчас я частично (5 часов в день) работаю в офисе на постоянной работе, которая нашла меня через фриланс, остальное время практически полностью посвящаю своим делам, лишь иногда откликаясь на работу от постоянных заказчиков, приобретенных на фрилансе.
</p>
<p></p>
<p>
В заключение хочу выразить огромную благодарность своей девушке Саше, которая была со мной и  поддерживала меня все это время.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/332/feed</wfw:commentRss>
		<slash:comments>298</slash:comments>
		</item>
		<item>
		<title>Ускоряем проект на Symfony через nginx+memcached</title>
		<link>http://job-interview.ru/articles/post/300</link>
		<comments>http://job-interview.ru/articles/post/300#comments</comments>
		<pubDate>Wed, 23 Feb 2011 15:11:09 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[memcache]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[symfony]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[фреймворки]]></category>

		<guid isPermaLink="false">/articles/?p=300</guid>
		<description><![CDATA[

Symfony — популярный фреймворк, использующий язык PHP, для ускорения процесса разработки web-приложений. Благодаря гибкой и продуманной структуре классов Symfony, программировать под этот фреймворк становится одним удовольствием, это действительно очень удобно.


Однако, плату за универсальность никто не отменял. И, хотя Symfony предоставляет обширные возможности для кэширования, оно не всегда спасает, особенно на нагруженных проектах и особенно на [...]]]></description>
			<content:encoded><![CDATA[<p><img src="/img/symfony_speed_up.jpg" border="0"></p>
<p>
<strong>Symfony</strong> — популярный фреймворк, использующий <strong>язык PHP</strong>, для ускорения процесса разработки web-приложений. Благодаря гибкой и продуманной структуре классов Symfony, программировать под этот <strong>фреймворк</strong> становится одним удовольствием, это действительно очень удобно.
</p>
<p>
Однако, плату за универсальность никто не отменял. И, хотя Symfony предоставляет обширные возможности для <strong>кэширования</strong>, оно не всегда спасает, особенно на нагруженных проектах и особенно на страницах, которые состоят из часто меняющихся блоков.
</p>
<p>
В этой статье я постараюсь описать <strong>минусы кэширования</strong> в Symfony и приемы их обхода.
</p>
<p><span id="more-300"></span></p>
<p>
Представьте ситуацию, когда есть страница, на которой данные могут меняться только раз в 1-2 суток, тогда мы смело можем ее закэшировать на 24 часа. В Symfony это делается очень просто установкой параметров в файле cache.yml для модулей:</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">enabled: true
with_layout: true
lifetime: <span style="">86400</span></pre></div></div>

</p>
<p>
Это означает, что раз в 24 часа при заходе одного пользователя страница будет перестраиваться, т. е. выполнять запросы к базе данных, исполнять <strong>код PHP</strong>, еще какие-то действия, после этого результат будет записан в кэш и отдан клиенту. После этого все последующие 24 часа каждый пользователь будет получать эту страницу из кэша — никаких запросов к базе, минимальное исполнение только самого необходимого кода. Красота!
</p>
<p>
И вот в один прекрасный момент руководство решает добавить на эту страницу блок с последними <em>комментариями пользователей</em>. Все, счастливая жизнь закончилась, пришло время пораскинуть мозгами. Думаю, очень многие <em>веб-разработчики</em> сталкивались с подобной историей.
</p>
<p>
Проблема в том, что блок с последними комментариями может обновиться как через минуту, так и через 2-3 часа, поэтому кэшировать всю страницу мы не можем, т. к. не понятно какое время жизни выставлять для кэша. Вообще это типичный случай, когда следует применять <strong>блочное кэширование</strong>, т. е. делим страницу на блоки (или компоненты в Symfony), каждому блоку задаем свои параметры кэширования.
</p>
<p>
Но такой тип кэширования далек от идеала, т. к. в этом случае Symfony придется выполнить большую часть своего кода. Код исполняется, как обычно, просто перед выполнением каждого блока будет проверка на наличие блока в кэше и, если он там есть и время жизни не истекло, то вместо выполнения этого блока будет просто вставлен html-код из кэша.<br />
При таком блочном кэшировании будет исполняться код Symfony при каждом <em>http-запросе</em>, кроме того, будет как минимум один <em>запрос к базе данных</em>, если пользователь авторизован &#8211;  Symfony получает данные о пользователе из базы еще до подключения блоков.
</p>
<p>
Однако, есть другой способ применения кэширования для случая, описанного выше. Для этого нам понадобится (я также привожу описание установки нужного ПО, для тех, кому оно понадобится, все примеры я проверял у себя на <em>Linux SUSE 11.3</em>):
</p>
<ul>
<li>
<strong>Nginx</strong> в качестве web-сервера</p>
<p><a href="#" onclick="jQuery('blockquote#nginx_install').toggle(); return false;" >Как установить и настроить Nginx</a></p>
<blockquote style="display: none;" id="nginx_install">
<p>
Скачиваем дистрибутив:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># wget http://sysoev.ru/nginx/nginx-0.8.54.tar.gz</span></pre></div></div>

<p>
Распаковываем его:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># tar zxf nginx-0.8.54.tar.gz</span></pre></div></div>

<p>
Переходим в созданную папку:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># cd nginx-0.8.54</span></pre></div></div>

<p>
Собираем и устанавливаем nginx:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># ./configure &amp;&amp; make &amp;&amp; make install</span></pre></div></div>

<p>
Для удобства работы с nginx создадим файл:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># touch /etc/init.d/nginx</span></pre></div></div>

<p>
И положим в него следующее содержимое:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;">#! /bin/bash</span>
&nbsp;
<span style="color: #666666; font-style: italic;">### BEGIN INIT INFO</span>
<span style="color: #666666; font-style: italic;"># Provides:          nginx</span>
<span style="color: #666666; font-style: italic;"># Required-Start:    $remote_fs $syslog $named $network $time</span>
<span style="color: #666666; font-style: italic;"># Required-Stop:     $remote_fs $syslog $named $network</span>
<span style="color: #666666; font-style: italic;"># Default-Start:     3 5</span>
<span style="color: #666666; font-style: italic;"># Default-Stop:      0 1 2 4 6</span>
<span style="color: #666666; font-style: italic;"># Short-Description: Start nginx at boot time</span>
<span style="color: #666666; font-style: italic;"># Description:       Enable service provided by nginx.</span>
<span style="color: #666666; font-style: italic;">### END INIT INFO</span>
&nbsp;
<span style="color: #007800;">PATH</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>sbin:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>bin:<span style="color: #000000; font-weight: bold;">/</span>sbin:<span style="color: #000000; font-weight: bold;">/</span>bin:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>sbin:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>bin
<span style="color: #007800;">NAME</span>=nginx
<span style="color: #007800;">DESC</span>=nginx
<span style="color: #007800;">PIDFILE</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>logs<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$NAME</span>.pid
<span style="color: #007800;">DAEMON</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>sbin<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$NAME</span>
<span style="color: #007800;">DAEMON_CONFIG</span>=<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf
&nbsp;
<span style="color: #7a0874; font-weight: bold;">test</span> <span style="color: #660033;">-x</span> <span style="color: #007800;">$DAEMON</span> <span style="color: #000000; font-weight: bold;">||</span> <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">0</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">set</span> <span style="color: #660033;">-e</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">case</span> <span style="color: #ff0000;">&quot;$1&quot;</span> <span style="color: #000000; font-weight: bold;">in</span>
  start<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Starting <span style="color: #007800;">$DESC</span>: &quot;</span>
        <span style="color: #007800;">$DAEMON</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; started&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  stop<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Stopping <span style="color: #007800;">$DESC</span>: &quot;</span>
 <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
                <span style="color: #c20cb9; font-weight: bold;">kill</span> <span style="color: #660033;">-15</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #000000; font-weight: bold;">`</span>
        <span style="color: #000000; font-weight: bold;">fi</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; stopped&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  restart<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Restarting <span style="color: #007800;">$DESC</span>: &quot;</span>
 <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
                <span style="color: #c20cb9; font-weight: bold;">kill</span> <span style="color: #660033;">-15</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #000000; font-weight: bold;">`</span>
        <span style="color: #000000; font-weight: bold;">fi</span>
        <span style="color: #c20cb9; font-weight: bold;">sleep</span> <span style="color: #000000;">1</span>
        <span style="color: #007800;">$DAEMON</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; restarted&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  reload<span style="color: #7a0874; font-weight: bold;">&#41;</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #660033;">-n</span> <span style="color: #ff0000;">&quot;Reloading <span style="color: #007800;">$DESC</span>: &quot;</span>
 <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span> <span style="color: #660033;">-f</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #7a0874; font-weight: bold;">&#93;</span>; <span style="color: #000000; font-weight: bold;">then</span>
        <span style="color: #c20cb9; font-weight: bold;">kill</span> <span style="color: #660033;">-HUP</span> <span style="color: #000000; font-weight: bold;">`</span><span style="color: #c20cb9; font-weight: bold;">cat</span> <span style="color: #007800;">$PIDFILE</span> <span style="color: #000000;">2</span><span style="color: #000000; font-weight: bold;">&gt;/</span>dev<span style="color: #000000; font-weight: bold;">/</span>null<span style="color: #000000; font-weight: bold;">`</span>
        <span style="color: #000000; font-weight: bold;">fi</span>
	<span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot; reloaded&quot;</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  configtest<span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #007800;">$DAEMON</span> <span style="color: #660033;">-t</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
  <span style="color: #000000; font-weight: bold;">*</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
        <span style="color: #007800;">N</span>=<span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>init.d<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$NAME</span>
        <span style="color: #7a0874; font-weight: bold;">echo</span> <span style="color: #ff0000;">&quot;Usage: <span style="color: #007800;">$N</span> {start|stop|status|restart|reload|configtest}&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;&amp;</span><span style="color: #000000;">2</span>
        <span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">1</span>
        <span style="color: #000000; font-weight: bold;">;;</span>
<span style="color: #000000; font-weight: bold;">esac</span> 
&nbsp;
<span style="color: #7a0874; font-weight: bold;">exit</span> <span style="color: #000000;">0</span></pre></div></div>

<p>
Стартуем nginx:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx start</span></pre></div></div>

<p>
Заходим на страницу http://localhost и видим:
</p>
<p>
«Welcome to nginx!»
</p>
<p><a href="#" onclick="jQuery('blockquote#nginx_install').toggle(); return false;" >свернуть</a></p>
</blockquote>
</li>
<li>
Фреймворк Symfony</p>
<p><a href="#" onclick="jQuery('blockquote#symfony_install').toggle(); return false;" >Как установить Symfony и настроить связку Nginx+Symfony</a></p>
<blockquote style="display: none;" id="symfony_install">
<p>
Заходим в папку, в которой будет находиться ваш проект Symfony. Далее выполняем команды:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># mkdir -p lib/vendor</span>
<span style="color: #666666; font-style: italic;"># cd lib/vendor/</span>
<span style="color: #666666; font-style: italic;"># wget http://www.symfony-project.org/get/symfony-1.4.8.tgz</span>
<span style="color: #666666; font-style: italic;"># tar zxpf symfony-1.4.8.tgz</span>
<span style="color: #666666; font-style: italic;"># mv symfony-1.4.8 symfony</span>
<span style="color: #666666; font-style: italic;"># cd ../../</span>
<span style="color: #666666; font-style: italic;"># php lib/vendor/symfony/data/bin/symfony generate:project PROJECT_NAME</span>
<span style="color: #666666; font-style: italic;"># php symfony generate:app frontend</span></pre></div></div>

<p>
Мы создали наш проект Symfony, теперь нужно настроить связку Nginx+Symfony. Находим файл conf/nginx.conf и заполняем его следующим:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">worker_processes  <span style="color: #000000;">1</span>;
&nbsp;
events <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    worker_connections  <span style="color: #000000;">1024</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
http <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    include       mime.types;
    default_type  application<span style="color: #000000; font-weight: bold;">/</span>octet-stream;
&nbsp;
    log_format  main  <span style="color: #ff0000;">'$remote_addr - $remote_user [$time_local] &quot;$request&quot; '</span>
                      <span style="color: #ff0000;">'$status $body_bytes_sent &quot;$http_referer&quot; '</span>
                      <span style="color: #ff0000;">'&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;'</span>;
&nbsp;
    access_log  logs<span style="color: #000000; font-weight: bold;">/</span>access.log  main;
    error_log  logs<span style="color: #000000; font-weight: bold;">/</span>error.log info;
&nbsp;
    sendfile        on;
    keepalive_timeout  <span style="color: #000000;">65</span>;
&nbsp;
    upstream fcgi_www <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	server 127.0.0.1:<span style="color: #000000;">9000</span>;
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
    server <span style="color: #7a0874; font-weight: bold;">&#123;</span>
        listen       <span style="color: #000000;">80</span>;
        server_name  localhost;
&nbsp;
        error_page   <span style="color: #000000;">500</span> <span style="color: #000000;">502</span> <span style="color: #000000;">503</span> <span style="color: #000000;">504</span>  <span style="color: #000000; font-weight: bold;">/</span>50x.html;
        location = <span style="color: #000000; font-weight: bold;">/</span>50x.html <span style="color: #7a0874; font-weight: bold;">&#123;</span>
            root   html;
        <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web</span>
&nbsp;
	location ~ <span style="color: #ff0000;">&quot;^(/css/|/images/|/js/|/uploads/)&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    expires 3d;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span>sf<span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>vendor<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>data<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/lib/vendor/symfony/data/web</span>
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    fastcgi_param REQUEST_URI            <span style="color: #007800;">$request_uri</span>;
	    fastcgi_param DOCUMENT_URI           <span style="color: #007800;">$document_uri</span>;
	    fastcgi_param DOCUMENT_ROOT          <span style="color: #007800;">$document_root</span>;
	    fastcgi_param GATEWAY_INTERFACE      CGI<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.1</span>;
	    fastcgi_param SERVER_SOFTWARE        nginx<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$nginx_version</span>;
	    fastcgi_param REMOTE_ADDR            <span style="color: #007800;">$remote_addr</span>;
	    fastcgi_param REMOTE_PORT            <span style="color: #007800;">$remote_port</span>;
	    fastcgi_param SERVER_ADDR            <span style="color: #007800;">$server_addr</span>;
	    fastcgi_param SERVER_PORT            <span style="color: #007800;">$server_port</span>;
	    fastcgi_param SERVER_NAME            <span style="color: #007800;">$server_name</span>;
	    fastcgi_param SERVER_PROTOCOL        <span style="color: #007800;">$server_protocol</span>;
	    fastcgi_param CONTENT_TYPE           <span style="color: #007800;">$content_type</span>;
	    fastcgi_param CONTENT_LENGTH         <span style="color: #007800;">$content_length</span>;
	    fastcgi_param HTTP_ACCEPT_ENCODING   <span style="color: #c20cb9; font-weight: bold;">gzip</span>,deflate;
	    fastcgi_param QUERY_STRING           <span style="color: #007800;">$query_string</span>;
	    fastcgi_param REDIRECT_STATUS        <span style="color: #000000;">200</span>;
	    fastcgi_param REQUEST_METHOD         <span style="color: #007800;">$request_method</span>;
	    fastcgi_param SCRIPT_FILENAME        <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>index.php; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web/index.php</span>
	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;
&nbsp;
	    fastcgi_pass  fcgi_www;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre></div></div>

<p>
Теперь осталось запустить <strong>PHP в режиме FastCGI</strong>:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php-cgi -a -b 127.0.0.1:9000 -c /etc/php5/fastcgi/php.ini</span></pre></div></div>

<p>
Если все правильно сделали, то по адресу http://localhost/ должна отобразиться страница примерно следующего содержания:
</p>
<p>
Symfony Project Created </p>
<p>Congratulations! You have successfully created your symfony project.
</p>
<p><a href="#" onclick="jQuery('blockquote#symfony_install').toggle(); return false;" >свернуть</a></p>
</blockquote>
</li>
<li>
<strong>Memcached</strong> и расширение для PHP</p>
<p><a href="#" onclick="jQuery('blockquote#memcached_install').toggle(); return false;" >Как установить memcached и расширение PHP к нему.</a></p>
<blockquote style="display: none;" id="memcached_install">
<p>
Устанавливаем memcached.
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># wget http://memcached.googlecode.com/files/memcached-1.4.5.tar.gz</span>
<span style="color: #666666; font-style: italic;"># tar zxf memcached-1.4.5.tar.gz</span>
<span style="color: #666666; font-style: italic;"># cd memcached-1.4.5/</span>
<span style="color: #666666; font-style: italic;"># ./configure</span></pre></div></div>

<p>
Если выскочит ошибка: <em>error: libevent is required.</em><br />
то устанавливаем libevent
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># cd ../</span>
<span style="color: #666666; font-style: italic;"># wget http://www.monkey.org/~provos/libevent-2.0.9-rc.tar.gz</span>
<span style="color: #666666; font-style: italic;"># tar zxf libevent-2.0.9-rc.tar.gz</span>
<span style="color: #666666; font-style: italic;"># cd libevent-2.0.9-rc/</span>
<span style="color: #666666; font-style: italic;"># ./configure</span>
<span style="color: #666666; font-style: italic;"># make &amp;&amp; make install</span></pre></div></div>

<p>
После этого продолжаем установку memcached:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># cd ../memcached-1.4.5/</span>
<span style="color: #666666; font-style: italic;"># ./configure</span>
<span style="color: #666666; font-style: italic;"># make &amp;&amp; make install</span></pre></div></div>

<p>
Устанавливаем расширение для PHP:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># pecl install memcache</span></pre></div></div>

<p>
После этого включаем расширение memcache.so в php.ini:
</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;"><span style="color: #000099;">extension</span><span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">memcache.so</span></pre></div></div>

<p>
Запускаем memcached:
</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/memcached start</span></pre></div></div>

<p><a href="#" onclick="jQuery('blockquote#memcached_install').toggle(); return false;" >свернуть</a></p>
</blockquote >
</li>
</ul>
<p>
Сейчас после открытия в браузере http://localhost мы видим страницу нашего проекта на Symfony.
</p>
<p>
Итак, у нас все есть для работы, начнем ускорять наш проект. За основу берется то, что Nginx умеет обращаться к memcached по ключу и отдавать значение, которое содержится по этому ключу, в качестве ответа web-сервера.
</p>
<p>
<strong>Memcached</strong> — это демон, который хранит данные в оперативной памяти, обращаться к этим данным мы можем по определенному ключу.
</p>
<p>
Воспользуемся всеми вышеописанными возможностями memcached и nginx. В качестве ключа в memcached мы будем использовать URL-адрес страниц нашего сайта, а в качестве содержимого HTML страницы. Теперь нам нужно настроить nginx так, чтобы он при наличии в memcached значения (html) по ключу (url страницы) отдавал его сразу же в ответе клиенту, в противном случае запрос должен передаваться к Symfony, который его обрабатывает, сохраняет в memcached и отдает ответ для клиента. Таким образом, если в данный момент страница не в кэше, то его добавит в кэш Symfony, и при следующем запросе к этой странице ответ будет получен еще на стороне nginx, не доходя даже до Symfony.
</p>
<p>
<img src="/img/nginx_memcached.png" border="0">
</p>
<p>
Итак, добавим в наш проект возможность записи ответа сервера в memcached. Для этого воспользуемся механизмом фильтров в Symfony. Создадим в директории lib нашего проекта поддиректорию cache, а в ней создадим файл sfHtmlCacheFilter.class.php. Содержимое этого файла будет следующее:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
&nbsp;
<span style="color: #000000; font-weight: bold;">class</span> sfHtmlCacheFilter <span style="color: #000000; font-weight: bold;">extends</span> sfFilter
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$multi_replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Метод вызывается после того, как страница полностью сформирована,
     * здесь содержимое страницы записывается в memcached, если она указана в конфиге html_cache.yml.
     *
     * @param &lt;Object&gt; $filterChain
     * @return &lt;NULL&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> execute <span style="color: #009900;">&#40;</span><span style="color: #000088;">$filterChain</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$filterChain</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">execute</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$response</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getResponse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// Если в наших конфигах прописано не использовать кэширование или мы находимся в debug-режиме, то прекращем выполнение.</span>
	<span style="color: #666666; font-style: italic;">// Здесь также проверяется код ответа - если он не равен 200, то прекращем выполнение.</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span>
          <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_cache'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getGetParameters</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getPostParameters</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
          <span style="color: #339933;">||</span>
          <span style="color: #009900;">&#40;</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_debug'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #339933;">!</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_no_script_name'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStatusCode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #cc66cc;">200</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
          <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000088;">$uri</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContext</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRouting</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getCurrentInternalUri</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getHost</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// Получаем запрошенный URI - будущий ключ для memcached</span>
        <span style="color: #000088;">$webUri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getUri</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$uriCacheParams</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// Получаем из конфига страницы, которые подлежат кэшированию</span>
        <span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getConfig</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$config</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$item</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$item</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$key</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$uriParams</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$routing_uri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^(.*)\?.*$/i'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'$1'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #666666; font-style: italic;">// Сравниваем запрошенный URI с записями в конфиге</span>
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'#^'</span><span style="color: #339933;">.</span><span style="color: #000088;">$key</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'$#'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$webUri</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$uriCacheParams</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$uriParams</span><span style="color: #339933;">;</span>
                    <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
	    <span style="color: #666666; font-style: italic;">// Если запрошенная страница есть в конфиге, то прекращаем цикл</span>
            <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uriCacheParams</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #000088;">$webUri</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span>_decodeUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$webUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$uriCacheParams</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getStatusCode</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">==</span> <span style="color: #0000ff;">'200'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
	    <span style="color: #666666; font-style: italic;">// Записываем содержимое ответа в кэш</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">setUri</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">.</span><span style="color: #000088;">$webUri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$response</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getContent</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uriCacheParams</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'lifetime'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Получить конфиг тэгов
     *
     * @return &lt;Array&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> getConfig<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$conf</span> <span style="color: #339933;">=</span> sfYaml<span style="color: #339933;">::</span><span style="color: #004000;">load</span><span style="color: #009900;">&#40;</span>sfConfig<span style="color: #339933;">::</span><span style="color: #004000;">get</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'sf_config_dir'</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">.</span> <span style="color: #0000ff;">'/html_cache.yml'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$conf</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Вызывается из методов save() моделей,
     * удаляет из кэша все страницы, зависящие от заданной модели
     *
     * @param &lt;Object&gt; $model - объект, для которого вызывается метод save в модели
     */</span>
    <span style="color: #000000; font-weight: bold;">public</span> static <span style="color: #000000; font-weight: bold;">function</span> deleteCache<span style="color: #009900;">&#40;</span><span style="color: #000088;">$model</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$request</span> <span style="color: #339933;">=</span> sfContext<span style="color: #339933;">::</span><span style="color: #004000;">getInstance</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getRequest</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$model_name</span> <span style="color: #339933;">=</span> <span style="color: #990000;">get_class</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$model</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$config</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getConfig</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #000088;">$arUri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Получаем страницы из конфига по этой модели</span>
        <span style="color: #000088;">$arCacheParam</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$config</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$model_name</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'http://'</span><span style="color: #339933;">.</span><span style="color: #000088;">$request</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getHost</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// Обходим в цикле страницы, строим из них ключи для memcache</span>
        <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arCacheParam</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$uri</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
            <span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$attr</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'attributes'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'attributes'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #990000;">settype</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'array'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$prop</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'get'</span><span style="color: #339933;">.</span><span style="color: #000088;">$prop</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">;</span>
                <span style="color: #009933; font-style: italic;">/**
                 * method_exists не работает для Doctrine,
                 * но работает для Propel, is_callable всегда будет
                 * возвращать true для Doctrine, поэтому существование
                 * метода проверяется таким образом.
                 */</span>
                try <span style="color: #009900;">&#123;</span>
                        <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$model</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$method</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                catch <span style="color: #009900;">&#40;</span>Exception <span style="color: #000088;">$e</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span>
&nbsp;
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">is_string</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">strpos</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">' '</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!==</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
                        <span style="color: #000088;">$value</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span>_decodeUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$value</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                    <span style="color: #009900;">&#125;</span>
                    <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$value</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #b1b100;">elseif</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/^pageLimit:(\d+)$/'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$prop</span><span style="color: #339933;">,</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$pageLimit</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
                    <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'pageLimit'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #990000;">range</span><span style="color: #009900;">&#40;</span><span style="color: #cc66cc;">1</span><span style="color: #339933;">,</span> <span style="color: #000088;">$pageLimit</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
            <span style="color: #000088;">$isCachable</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$beforeDeleteCache</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'beforeDeleteCache'</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> ? <span style="color: #000088;">$param</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'beforeDeleteCache'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">:</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #990000;">settype</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$beforeDeleteCache</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'array'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$beforeDeleteCache</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$callback</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$method</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$callback</span><span style="color: #339933;">;</span>
                <span style="color: #000088;">$isCachable</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$model</span><span style="color: #339933;">-&gt;</span><span style="color: #000088;">$method</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
&nbsp;
            <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$isCachable</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000088;">$uri</span> <span style="color: #339933;">=</span> <span style="color: #990000;">preg_replace_callback</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/\(.*\)/U'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'self'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'replace_attr_callback'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #009900;">&#41;</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">replace_multi_attr</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
                <span style="color: #b1b100;">else</span>
                <span style="color: #009900;">&#123;</span>
                    <span style="color: #000088;">$arUri</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">.</span><span style="color: #000088;">$uri</span><span style="color: #339933;">;</span>
                <span style="color: #009900;">&#125;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #666666; font-style: italic;">// Удаляем массив страниц из memcached</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">deleteUri</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Используется для парсинга конфига при удалении страницы из memcached
     *
     * @param &lt;Array&gt; $matches
     * @return &lt;String&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> replace_attr_callback<span style="color: #009900;">&#40;</span><span style="color: #000088;">$matches</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$expr</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$matches</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$arKeys</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_keys</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$key</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$arKeys</span><span style="color: #009900;">&#91;</span><span style="color: #cc66cc;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #990000;">is_array</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">!==</span> <span style="color: #0000ff;">'pageLimit'</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">&amp;&amp;</span> <span style="color: #990000;">preg_match</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'/'</span><span style="color: #339933;">.</span><span style="color: #000088;">$expr</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'/'</span><span style="color: #339933;">,</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$expr</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">else</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
            <span style="color: #000088;">$expr</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'%MULTI_REPLACEMENT_'</span><span style="color: #339933;">.</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$multi_replacement</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">-</span> <span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'%'</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$replacement</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #000088;">$expr</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Используется для парсинга конфига при удалении страницы из memcached
     *
     * @param &lt;Array&gt; $attr
     * @param &lt;String&gt; $uri
     * @param &lt;Array&gt; $arUri
     * @param &lt;Integer&gt; $key
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> replace_multi_attr<span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #339933;">&amp;</span><span style="color: #000088;">$arUri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$key</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">isset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$key</span><span style="color: #009900;">&#93;</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$ind</span><span style="color: #339933;">=&gt;</span><span style="color: #000088;">$i</span><span style="color: #009900;">&#41;</span>
            <span style="color: #009900;">&#123;</span>
                <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">replace_multi_attr</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #339933;">,</span>
                                <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'%MULTI_REPLACEMENT_'</span><span style="color: #339933;">.</span><span style="color: #000088;">$key</span><span style="color: #339933;">.</span><span style="color: #0000ff;">'%'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$i</span><span style="color: #339933;">,</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
                                <span style="color: #000088;">$arUri</span><span style="color: #339933;">,</span>
                                <span style="color: #000088;">$key</span><span style="color: #339933;">+</span><span style="color: #cc66cc;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #009900;">&#125;</span>
        <span style="color: #009900;">&#125;</span>
        <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$key</span> <span style="color: #339933;">==</span> <span style="color: #990000;">count</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$attr</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$arUri</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #000088;">$host</span><span style="color: #339933;">.</span><span style="color: #000088;">$uri</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Возвращает объект для работы с memcached.
     *
     * @return &lt;Object&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> getMemcache<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$memcache</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Memcache<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$con</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$memcache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">connect</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'127.0.0.1'</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">11211</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">return</span> <span style="color: #000088;">$memcache</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Записываем содержимое страницы в memcached
     *
     * @param &lt;String&gt; $uri - ключ в memcached
     * @param &lt;String&gt; $data - значение в memcached
     * @param &lt;Integer&gt; $lifetime - время жизни кэша
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static  <span style="color: #000000; font-weight: bold;">function</span> setUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #339933;">,</span> <span style="color: #000088;">$lifetime</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
	<span style="color: #000088;">$memcache</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getMemcache</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #000088;">$memcache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">set</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$data</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">0</span><span style="color: #339933;">,</span> <span style="color: #000088;">$lifetime</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Удаляет страницу из memcached
     *
     * @param &lt;Array&gt; $arUri - массив ключей memcached,
     * которые следует удалить
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> deleteUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #990000;">settype</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'array'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #000088;">$memcache</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">self</span><span style="color: #339933;">::</span><span style="color: #004000;">getMemcache</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">foreach</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$arUri</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#123;</span>
            <span style="color: #000088;">$memcache</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">delete</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
&nbsp;
    <span style="color: #009933; font-style: italic;">/**
     * Метод декодирует URI через rawurldecode,
     * но символ пробела оставляет в прежнем виде,
     * т.к. nginx его не декодирует в своей переменной $uri
     *
     * @param &lt;string&gt; $uri
     * @param &lt;boolean&gt; $decode
     * @return &lt;string&gt;
     */</span>
    <span style="color: #000000; font-weight: bold;">private</span> static <span style="color: #000000; font-weight: bold;">function</span> _decodeUri<span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #339933;">,</span> <span style="color: #000088;">$decode</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
        <span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$decode</span> ? <span style="color: #990000;">rawurldecode</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$uri</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">:</span> <span style="color: #000088;">$encodedUri</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
        <span style="color: #b1b100;">return</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">' '</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'%20'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>
Пока нас будет интересовать только первый метод класса execute. Он вызывается после того, как закончено формирование страницы, в этом методе у нас есть возможность обратиться к содержимому страницы, еще до того, как она отправлена клиенту.
</p>
<p>
Все, что делается в методе execute — это получение текущего адреса страницы, проверка его в конфиге html_cache.yml и, если он там есть, записываем содержимое в memcached.
</p>
<p>
Теперь создадим сам конфиг html_cache.yml и положим его в папку config нашего проекта:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">Index:
  /: <span style="">&#123;</span> lifetime: <span style="">86400</span> <span style="">&#125;</span></pre></div></div>

</p>
<p>
Здесь мы задаем адрес запрошенной страницы («/» &#8211; запрос главной страницы сайта), в фигурных скобках перечислены параметры кэширования, мы указали время жизни кэша 86400 секунд, т. е. сутки. Параметр Index сейчас используется только лишь в качестве группировки адресов страниц, но здесь можно также указывать названия <strong>моделей Symfony</strong>, об этом будет рассказано ниже.
</p>
<p>
По части Symfony у нас почти все готово, осталось включить использование кэширования и активировать наш фильтр.
</p>
<p>
Чтобы включить кэширование для секции prod прописываем в файле apps/frontend/config/settings.yml (изменения выделены жирным шрифтом):
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
</pre>
</td>
<td class="code">
<pre class="ini" style="font-family:monospace;">prod:
  .settings:
    no_script_name:         true
    <b>cache:               true</b>
    logging_enabled:        true</pre>
</td>
</tr>
</table>
</div>
<p>А теперь активируем фильтр, добавляем в файл apps/frontend/config/filters.yml пару строчек:</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
</pre>
</td>
<td class="code">
<pre class="ini" style="font-family:monospace;">rendering: ~
security:  ~
&nbsp;
# insert your own filters here
&nbsp;
<b>htmlcache:
    class: sfHtmlCacheFilter</b>
&nbsp;
cache:     ~
execution: ~</pre>
</td>
</tr>
</table>
</div>
<p>
Тем самым мы активировали наш класс-фильтр.
</p>
<p>
Теперь сбрасываем <strong>кэш Symfony</strong>:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony cache:clear</span></pre></div></div>

</p>
<p>
И заходим на страницу http://localhost/ . Если все правильно сделали главная страница нашего сайта должна оказаться в memcached, проверяем:
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
</pre>
</td>
<td class="code">
<pre class="html" style="font-family:monospace;"><b># telnet localhost 11211</b>
Trying ::1...
telnet: connect to address ::1: Connection refused
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
<b>get http://localhost/</b>
VALUE http://localhost/ 0 2026
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;

&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot; xml:lang=&quot;en&quot; lang=&quot;en&quot;&gt;
&lt;head&gt;
&nbsp;
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=utf-8&quot; /&gt;

&lt;title&gt;&lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;/css/main.css&quot; /&gt;

&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;/sf/sf_default/css/screen.css&quot; /&gt;
&nbsp;
&lt;link rel=&quot;shortcut icon&quot; href=&quot;/favicon.ico&quot; /&gt;

&nbsp;
&lt;!--[if lt IE 7.]&gt;
&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; media=&quot;screen&quot; href=&quot;/sf/sf_default/css/ie.css&quot; /&gt;

&lt;![endif]--&gt;
&nbsp;
&lt;/head&gt;
&lt;body&gt;
&lt;div class=&quot;sfTContainer&quot;&gt;
  &lt;a href=&quot;http://www.symfony-project.org/&quot;&gt;&lt;img alt=&quot;symfony PHP Framework&quot; class=&quot;sfTLogo&quot; src=&quot;/sf/sf_default/images/sfTLogo.png&quot; height=&quot;39&quot; width=&quot;186&quot; /&gt;&lt;/a&gt;

&lt;div class=&quot;sfTMessageContainer sfTMessage&quot;&gt;
  &lt;img alt=&quot;ok&quot; class=&quot;sfTMessageIcon&quot; src=&quot;/sf/sf_default/images/icons/ok48.png&quot; height=&quot;48&quot; width=&quot;48&quot; /&gt;  &lt;div class=&quot;sfTMessageWrap&quot;&gt;

    &lt;h1&gt;Symfony Project Created&lt;/h1&gt;
    &lt;h5&gt;Congratulations! You have successfully created your symfony project.&lt;/h5&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;dl class=&quot;sfTMessageInfo&quot;&gt;

  &lt;dt&gt;Project setup successful&lt;/dt&gt;
  &lt;dd&gt;This project uses the symfony libraries. If you see no image in this page, you may need to configure your web server so that it gains access to the &lt;code&gt;symfony_data/web/sf/&lt;/code&gt; directory.&lt;/dd&gt;
&nbsp;
  &lt;dt&gt;This is a temporary page&lt;/dt&gt;

  &lt;dd&gt;This page is part of the symfony &lt;code&gt;default&lt;/code&gt; module. It will disappear as soon as you define a &lt;code&gt;homepage&lt;/code&gt; route in your &lt;code&gt;routing.yml&lt;/code&gt;.&lt;/dd&gt;

&nbsp;
  &lt;dt&gt;What's next&lt;/dt&gt;
  &lt;dd&gt;
    &lt;ul class=&quot;sfTIconList&quot;&gt;
      &lt;li class=&quot;sfTDatabaseMessage&quot;&gt;Create your data model&lt;/li&gt;

      &lt;li class=&quot;sfTColorMessage&quot;&gt;Customize the layout of the generated templates&lt;/li&gt;
      &lt;li class=&quot;sfTLinkMessage&quot;&gt;&lt;a href=&quot;http://www.symfony-project.org/doc&quot;&gt;Learn more from the online documentation&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;

  &lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
&nbsp;
END
<b>quit</b>
Connection closed by foreign host.</pre>
</td>
</tr>
</table>
</div>
<p>
Отлично! Теперь наш проект может перед отдачей ответа клиенту записывать в memcached HTML страниц.
</p>
<p>
Ну а теперь осталось настроить nginx, чтобы он мог сам отвечать клиенту, если запрошенная страница присутствует в memcached.
</p>
<p>
Для этого нам надо добавить еще один <strong>upstream для memcached</strong> в конфиг nginx и задать правила для проксирования в него запросов. Вот каким должен получиться конфиг для Nginx (изменения выделены жирным шрифтом):
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
</pre>
</td>
<td class="code">
<pre class="bash" style="font-family:monospace;">worker_processes  <span style="color: #000000;">1</span>;
&nbsp;
&nbsp;
events <span style="color: #7a0874; font-weight: bold;">&#123;</span>
    worker_connections  <span style="color: #000000;">1024</span>;
<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
&nbsp;
http <span style="color: #7a0874; font-weight: bold;">&#123;</span>

    include       mime.types;
    default_type  application<span style="color: #000000; font-weight: bold;">/</span>octet-stream;
&nbsp;
    log_format  main  <span style="color: #ff0000;">'$remote_addr - $remote_user [$time_local] &quot;$request&quot; '</span>
                      <span style="color: #ff0000;">'$status $body_bytes_sent &quot;$http_referer&quot; '</span>

                      <span style="color: #ff0000;">'&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;'</span>;
&nbsp;
    access_log  logs<span style="color: #000000; font-weight: bold;">/</span>access.log  main;
    error_log  logs<span style="color: #000000; font-weight: bold;">/</span>error.log info;
&nbsp;
    sendfile        on;
    keepalive_timeout  <span style="color: #000000;">65</span>;

&nbsp;
    <b>upstream memcached_backend <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	server 127.0.0.1:<span style="color: #000000;">11211</span>;
    <span style="color: #7a0874; font-weight: bold;">&#125;</span></b>
&nbsp;
    upstream fcgi_www <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	server 127.0.0.1:<span style="color: #000000;">9000</span>;
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>

&nbsp;
    server <span style="color: #7a0874; font-weight: bold;">&#123;</span>
        listen       <span style="color: #000000;">80</span>;
        server_name  localhost;
&nbsp;
        error_page   <span style="color: #000000;">500</span> <span style="color: #000000;">502</span> <span style="color: #000000;">503</span> <span style="color: #000000;">504</span>  <span style="color: #000000; font-weight: bold;">/</span>50x.html;
        location = <span style="color: #000000; font-weight: bold;">/</span>50x.html <span style="color: #7a0874; font-weight: bold;">&#123;</span>

            root   html;
        <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web</span>
&nbsp;

	location ~ <span style="color: #ff0000;">&quot;^(/css/|/images/|/js/|/uploads/)&quot;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    expires 3d;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span>sf<span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    root <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>vendor<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>data<span style="color: #000000; font-weight: bold;">/</span>web; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/lib/vendor/symfony/data/web</span>

	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    fastcgi_param REQUEST_URI            <span style="color: #007800;">$request_uri</span>;
	    fastcgi_param DOCUMENT_URI           <span style="color: #007800;">$document_uri</span>;
	    fastcgi_param DOCUMENT_ROOT          <span style="color: #007800;">$document_root</span>;
	    fastcgi_param GATEWAY_INTERFACE      CGI<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.1</span>;
	    fastcgi_param SERVER_SOFTWARE        nginx<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$nginx_version</span>;
	    fastcgi_param REMOTE_ADDR            <span style="color: #007800;">$remote_addr</span>;
	    fastcgi_param REMOTE_PORT            <span style="color: #007800;">$remote_port</span>;
	    fastcgi_param SERVER_ADDR            <span style="color: #007800;">$server_addr</span>;
	    fastcgi_param SERVER_PORT            <span style="color: #007800;">$server_port</span>;
	    fastcgi_param SERVER_NAME            <span style="color: #007800;">$server_name</span>;
	    fastcgi_param SERVER_PROTOCOL        <span style="color: #007800;">$server_protocol</span>;
	    fastcgi_param CONTENT_TYPE           <span style="color: #007800;">$content_type</span>;
	    fastcgi_param CONTENT_LENGTH         <span style="color: #007800;">$content_length</span>;
	    fastcgi_param HTTP_ACCEPT_ENCODING   <span style="color: #c20cb9; font-weight: bold;">gzip</span>,deflate;
	    fastcgi_param QUERY_STRING           <span style="color: #007800;">$query_string</span>;
	    fastcgi_param REDIRECT_STATUS        <span style="color: #000000;">200</span>;
	    fastcgi_param REQUEST_METHOD         <span style="color: #007800;">$request_method</span>;
	    fastcgi_param SCRIPT_FILENAME        <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>index.php; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web/index.php</span>

	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;
&nbsp;
            <b><span style="color: #666666; font-style: italic;"># Если это POST-запрос, то передаем обработку сразу в Symfony</span>
	    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">$request_method</span> = POST<span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">&#123;</span>

		fastcgi_pass  fcgi_www;
		<span style="color: #7a0874; font-weight: bold;">break</span>;
	    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
           <span style="color: #666666; font-style: italic;"># Если на предыдущем шаге мы не вышли из location'а, то это GET-запрос.</span>
           <span style="color: #666666; font-style: italic;"># Устанавливаем ключ для memcached, по которому будем искать значение</span>
	    <span style="color: #000000; font-weight: bold;">set</span> <span style="color: #007800;">$memcached_key</span> <span style="color: #ff0000;">&quot;http://<span style="color: #007800;">$host</span><span style="color: #007800;">$uri</span>&quot;</span>;
           <span style="color: #666666; font-style: italic;"># Задаем upstream для memcached</span>

	    memcached_pass  memcached_backend;
&nbsp;
           <span style="color: #666666; font-style: italic;"># Устанавливаем тип содержимого, полученного от memcached, у нас хранится HTML</span>
	    default_type text<span style="color: #000000; font-weight: bold;">/</span>html;
           <span style="color: #666666; font-style: italic;"># Указываем nginx'у переходить в именованный location @symfony в случае отсутствия ключа </span>
           <span style="color: #666666; font-style: italic;"># в memcached или в случае возникновении ошибки при запросе к memcached</span>
	    proxy_intercept_errors  on;
	    error_page <span style="color: #000000;">404</span> <span style="color: #000000;">502</span> = <span style="color: #000000; font-weight: bold;">@</span>symfony;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>

&nbsp;
       <span style="color: #666666; font-style: italic;"># Здесь описан именованный location, куда nginx переходит в случае отсутствия ключа или                                          </span>
       <span style="color: #666666; font-style: italic;"># возникновении ошибки при обращении к memcached. Здесь просто перечислены параметры </span>
       <span style="color: #666666; font-style: italic;"># fastcgi так же, как было сделано выше.</span>
	location <span style="color: #000000; font-weight: bold;">@</span>symfony <span style="color: #7a0874; font-weight: bold;">&#123;</span>
	    fastcgi_param REQUEST_URI            <span style="color: #007800;">$request_uri</span>;
	    fastcgi_param DOCUMENT_URI           <span style="color: #007800;">$document_uri</span>;
	    fastcgi_param DOCUMENT_ROOT          <span style="color: #007800;">$document_root</span>;
	    fastcgi_param GATEWAY_INTERFACE      CGI<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1.1</span>;
	    fastcgi_param SERVER_SOFTWARE        nginx<span style="color: #000000; font-weight: bold;">/</span><span style="color: #007800;">$nginx_version</span>;
	    fastcgi_param REMOTE_ADDR            <span style="color: #007800;">$remote_addr</span>;
	    fastcgi_param REMOTE_PORT            <span style="color: #007800;">$remote_port</span>;
	    fastcgi_param SERVER_ADDR            <span style="color: #007800;">$server_addr</span>;
	    fastcgi_param SERVER_PORT            <span style="color: #007800;">$server_port</span>;
	    fastcgi_param SERVER_NAME            <span style="color: #007800;">$server_name</span>;
	    fastcgi_param SERVER_PROTOCOL        <span style="color: #007800;">$server_protocol</span>;
	    fastcgi_param CONTENT_TYPE           <span style="color: #007800;">$content_type</span>;
	    fastcgi_param CONTENT_LENGTH         <span style="color: #007800;">$content_length</span>;
	    fastcgi_param HTTP_ACCEPT_ENCODING   <span style="color: #c20cb9; font-weight: bold;">gzip</span>,deflate;
	    fastcgi_param QUERY_STRING           <span style="color: #007800;">$query_string</span>;
	    fastcgi_param REDIRECT_STATUS        <span style="color: #000000;">200</span>;
	    fastcgi_param REQUEST_METHOD         <span style="color: #007800;">$request_method</span>;
	    fastcgi_param SCRIPT_FILENAME        <span style="color: #000000; font-weight: bold;">/</span>srv<span style="color: #000000; font-weight: bold;">/</span>www<span style="color: #000000; font-weight: bold;">/</span>symfony<span style="color: #000000; font-weight: bold;">/</span>web<span style="color: #000000; font-weight: bold;">/</span>index.php; <span style="color: #666666; font-style: italic;">#%ПУТЬ_ДО_ВАШЕГО_ПРОЕКТА%/web/index.php</span>

	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;
	    fastcgi_pass  fcgi_www;
	<span style="color: #7a0874; font-weight: bold;">&#125;</span></b>
    <span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
<span style="color: #7a0874; font-weight: bold;">&#125;</span></pre>
</td>
</tr>
</table>
</div>
<p>
Теперь проверяем нет ли ошибок в конфигах Nginx после внесения изменений:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx configtest</span>
the configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf syntax is ok
configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf <span style="color: #7a0874; font-weight: bold;">test</span> is successful</pre></div></div>

</p>
<p>
И говорим Nginx, чтобы он перечитал конфиг:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx reload</span>
Reloading nginx:  reloaded</pre></div></div>

</p>
<p>
Проверяем! Заходим на страницу http://localhost/ , она у нас уже должна лежать в memcached. Лично я в своем браузере Mozilla Firefox даже на примере такой простой странички вижу, что она стала загружаться гораздо быстрее!
</p>
<p>
Но не будем доверять всему тому, что видим. Проведем небольшой бенчмарк, в этом нам поможет утилита <strong>ab2</strong> — инструмент от разработчиков <strong>web-сервера Apache</strong>.
</p>
<p>
Сначала закомментируем наши <strong>настройки в Nginx</strong>, чтобы он перенаправлял все на Symfony.
</p>
<p>
Вносим следующие изменения в наш конфиг для Nginx, начиная с 71-й строки:
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
</pre>
</td>
<td class="code">
<pre class="bash" style="font-family:monospace;">	    fastcgi_param SCRIPT_NAME            <span style="color: #000000; font-weight: bold;">/</span>index.php;
	    fastcgi_param PATH_INFO              <span style="color: #007800;">$request_uri</span>;<b>
	    fastcgi_pass  fcgi_www;
&nbsp;
<span style="color: #666666; font-style: italic;">#	    if ($request_method = POST) {</span>

<span style="color: #666666; font-style: italic;">#		fastcgi_pass  fcgi_www;</span>
<span style="color: #666666; font-style: italic;">#		break;</span>
<span style="color: #666666; font-style: italic;">#	    }</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#	    set $memcached_key &quot;http://$host$uri&quot;;</span>
<span style="color: #666666; font-style: italic;">#	    memcached_pass  memcached_backend;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">#	    default_type text/html;</span>
<span style="color: #666666; font-style: italic;">#	    proxy_intercept_errors  on;</span>

<span style="color: #666666; font-style: italic;">#	    error_page 404 502 = @symfony;</span></b>
	<span style="color: #7a0874; font-weight: bold;">&#125;</span>
&nbsp;
	location <span style="color: #000000; font-weight: bold;">@</span>symfony <span style="color: #7a0874; font-weight: bold;">&#123;</span></pre>
</td>
</tr>
</table>
</div>
</pre>
<p>
Затем стандартные команды:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx configtest</span>
the configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf syntax is ok
configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf <span style="color: #7a0874; font-weight: bold;">test</span> is successful
<span style="color: #666666; font-style: italic;"># /etc/init.d/nginx reload</span>
Reloading nginx:  reloaded</pre></div></div>

</p>
<p>
И запускаем утилиту от Apache,  отправим на наш сайт 1000 запросов, причем 10 будем выполнять параллельно:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># ab2 -n 1000 -c 10 http://127.0.0.1:80/</span>
This is ApacheBench, Version <span style="color: #000000;">2.3</span> <span style="color: #000000; font-weight: bold;">&lt;</span><span style="color: #007800;">$Revision</span>: <span style="color: #000000;">655654</span> $<span style="color: #000000; font-weight: bold;">&gt;</span>
Copyright <span style="color: #000000;">1996</span> Adam Twiss, Zeus Technology Ltd, http:<span style="color: #000000; font-weight: bold;">//</span>www.zeustech.net<span style="color: #000000; font-weight: bold;">/</span>
Licensed to The Apache Software Foundation, http:<span style="color: #000000; font-weight: bold;">//</span>www.apache.org<span style="color: #000000; font-weight: bold;">/</span>
&nbsp;
Benchmarking 127.0.0.1 <span style="color: #7a0874; font-weight: bold;">&#40;</span>be patient<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Completed <span style="color: #000000;">100</span> requests
Completed <span style="color: #000000;">200</span> requests
Completed <span style="color: #000000;">300</span> requests
Completed <span style="color: #000000;">400</span> requests
Completed <span style="color: #000000;">500</span> requests
Completed <span style="color: #000000;">600</span> requests
Completed <span style="color: #000000;">700</span> requests
Completed <span style="color: #000000;">800</span> requests
Completed <span style="color: #000000;">900</span> requests
Completed <span style="color: #000000;">1000</span> requests
Finished <span style="color: #000000;">1000</span> requests
&nbsp;
Server Software:        nginx<span style="color: #000000; font-weight: bold;">/</span>0.8.54
Server Hostname:        127.0.0.1
Server Port:            <span style="color: #000000;">80</span>
&nbsp;
Document Path:          <span style="color: #000000; font-weight: bold;">/</span>
Document Length:        <span style="color: #000000;">2026</span> bytes
&nbsp;
Concurrency Level:      <span style="color: #000000;">10</span>
Time taken <span style="color: #000000; font-weight: bold;">for</span> tests:   <span style="color: #000000;">26.412</span> seconds
Complete requests:      <span style="color: #000000;">1000</span>
Failed requests:        <span style="color: #000000;">646</span>
   <span style="color: #7a0874; font-weight: bold;">&#40;</span>Connect: <span style="color: #000000;">0</span>, Receive: <span style="color: #000000;">0</span>, Length: <span style="color: #000000;">646</span>, Exceptions: <span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
Write errors:           <span style="color: #000000;">0</span>
Non-2xx responses:      <span style="color: #000000;">646</span>
Total transferred:      <span style="color: #000000;">1142110</span> bytes
HTML transferred:       <span style="color: #000000;">964622</span> bytes
Requests per second:    <span style="color: #000000;">37.86</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #666666; font-style: italic;">#/sec] (mean)</span>
Time per request:       <span style="color: #000000;">264.116</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Time per request:       <span style="color: #000000;">26.412</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean, across all concurrent requests<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Transfer rate:          <span style="color: #000000;">42.23</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>Kbytes<span style="color: #000000; font-weight: bold;">/</span>sec<span style="color: #7a0874; font-weight: bold;">&#93;</span> received
&nbsp;
Connection Times <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
              min  mean<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #000000; font-weight: bold;">/</span>-sd<span style="color: #7a0874; font-weight: bold;">&#93;</span> median   max
Connect:        <span style="color: #000000;">0</span>    <span style="color: #000000;">0</span>   <span style="color: #000000;">0.1</span>      <span style="color: #000000;">0</span>       <span style="color: #000000;">1</span>
Processing:     <span style="color: #000000;">0</span>  <span style="color: #000000;">264</span> <span style="color: #000000;">349.9</span>      <span style="color: #000000;">3</span>     <span style="color: #000000;">827</span>
Waiting:        <span style="color: #000000;">0</span>  <span style="color: #000000;">264</span> <span style="color: #000000;">349.9</span>      <span style="color: #000000;">3</span>     <span style="color: #000000;">810</span>
Total:          <span style="color: #000000;">1</span>  <span style="color: #000000;">264</span> <span style="color: #000000;">349.9</span>      <span style="color: #000000;">3</span>     <span style="color: #000000;">827</span>
&nbsp;
Percentage of the requests served within a certain <span style="color: #000000; font-weight: bold;">time</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
  <span style="color: #000000;">50</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">3</span>
  <span style="color: #000000;">66</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">703</span>
  <span style="color: #000000;">75</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">713</span>
  <span style="color: #000000;">80</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">716</span>
  <span style="color: #000000;">90</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">748</span>
  <span style="color: #000000;">95</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">788</span>
  <span style="color: #000000;">98</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">790</span>
  <span style="color: #000000;">99</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">796</span>
 <span style="color: #000000;">100</span><span style="color: #000000; font-weight: bold;">%</span>    <span style="color: #000000;">827</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>longest request<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

</p>
<p>
У меня после таких тестов отваливался через некоторое время <strong>fastcgi</strong>. Во время выполнения ab2 попробуйте проверить загрузку страницы в браузере — можно наблюдать постепенное нарастание тормозов при загрузке страницы.
</p>
<p>
Итак, если вас настигла беда с fastcgi, как и у меня, то запускаем его снова:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">php-cgi <span style="color: #660033;">-a</span> <span style="color: #660033;">-b</span> 127.0.0.1:<span style="color: #000000;">9000</span> <span style="color: #660033;">-c</span> <span style="color: #000000; font-weight: bold;">/</span>etc<span style="color: #000000; font-weight: bold;">/</span>php5<span style="color: #000000; font-weight: bold;">/</span>fastcgi<span style="color: #000000; font-weight: bold;">/</span>php.ini</pre></div></div>

</p>
<p>
Далее убираем наши комментарии, сделанные перед запуском теста, релоадим nginx и запускаем ab2 с теми же параметрами:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># /etc/init.d/nginx configtest</span>
the configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf syntax is ok
configuration <span style="color: #c20cb9; font-weight: bold;">file</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>nginx<span style="color: #000000; font-weight: bold;">/</span>conf<span style="color: #000000; font-weight: bold;">/</span>nginx.conf <span style="color: #7a0874; font-weight: bold;">test</span> is successful
<span style="color: #666666; font-style: italic;"># /etc/init.d/nginx reload</span>
Reloading nginx:  reloaded
<span style="color: #666666; font-style: italic;"># ab2 -n 1000 -c 10 http://127.0.0.1:80/</span>
This is ApacheBench, Version <span style="color: #000000;">2.3</span> <span style="color: #000000; font-weight: bold;">&lt;</span><span style="color: #007800;">$Revision</span>: <span style="color: #000000;">655654</span> $<span style="color: #000000; font-weight: bold;">&gt;</span>
Copyright <span style="color: #000000;">1996</span> Adam Twiss, Zeus Technology Ltd, http:<span style="color: #000000; font-weight: bold;">//</span>www.zeustech.net<span style="color: #000000; font-weight: bold;">/</span>
Licensed to The Apache Software Foundation, http:<span style="color: #000000; font-weight: bold;">//</span>www.apache.org<span style="color: #000000; font-weight: bold;">/</span>
&nbsp;
Benchmarking 127.0.0.1 <span style="color: #7a0874; font-weight: bold;">&#40;</span>be patient<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Completed <span style="color: #000000;">100</span> requests
Completed <span style="color: #000000;">200</span> requests
Completed <span style="color: #000000;">300</span> requests
Completed <span style="color: #000000;">400</span> requests
Completed <span style="color: #000000;">500</span> requests
Completed <span style="color: #000000;">600</span> requests
Completed <span style="color: #000000;">700</span> requests
Completed <span style="color: #000000;">800</span> requests
Completed <span style="color: #000000;">900</span> requests
Completed <span style="color: #000000;">1000</span> requests
Finished <span style="color: #000000;">1000</span> requests
&nbsp;
Server Software:        nginx<span style="color: #000000; font-weight: bold;">/</span>0.8.54
Server Hostname:        127.0.0.1
Server Port:            <span style="color: #000000;">80</span>
&nbsp;
Document Path:          <span style="color: #000000; font-weight: bold;">/</span>
Document Length:        <span style="color: #000000;">2026</span> bytes
&nbsp;
Concurrency Level:      <span style="color: #000000;">10</span>
Time taken <span style="color: #000000; font-weight: bold;">for</span> tests:   <span style="color: #000000;">0.337</span> seconds
Complete requests:      <span style="color: #000000;">1000</span>
Failed requests:        <span style="color: #000000;">0</span>
Write errors:           <span style="color: #000000;">0</span>
Total transferred:      <span style="color: #000000;">2170000</span> bytes
HTML transferred:       <span style="color: #000000;">2026000</span> bytes
Requests per second:    <span style="color: #000000;">2971.65</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #666666; font-style: italic;">#/sec] (mean)</span>
Time per request:       <span style="color: #000000;">3.365</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Time per request:       <span style="color: #000000;">0.337</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>ms<span style="color: #7a0874; font-weight: bold;">&#93;</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>mean, across all concurrent requests<span style="color: #7a0874; font-weight: bold;">&#41;</span>
Transfer rate:          <span style="color: #000000;">6297.35</span> <span style="color: #7a0874; font-weight: bold;">&#91;</span>Kbytes<span style="color: #000000; font-weight: bold;">/</span>sec<span style="color: #7a0874; font-weight: bold;">&#93;</span> received
&nbsp;
Connection Times <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
              min  mean<span style="color: #7a0874; font-weight: bold;">&#91;</span>+<span style="color: #000000; font-weight: bold;">/</span>-sd<span style="color: #7a0874; font-weight: bold;">&#93;</span> median   max
Connect:        <span style="color: #000000;">0</span>    <span style="color: #000000;">0</span>   <span style="color: #000000;">0.4</span>      <span style="color: #000000;">0</span>       <span style="color: #000000;">3</span>
Processing:     <span style="color: #000000;">1</span>    <span style="color: #000000;">3</span>   <span style="color: #000000;">0.6</span>      <span style="color: #000000;">3</span>       <span style="color: #000000;">5</span>
Waiting:        <span style="color: #000000;">0</span>    <span style="color: #000000;">3</span>   <span style="color: #000000;">0.6</span>      <span style="color: #000000;">3</span>       <span style="color: #000000;">4</span>
Total:          <span style="color: #000000;">1</span>    <span style="color: #000000;">3</span>   <span style="color: #000000;">0.5</span>      <span style="color: #000000;">3</span>       <span style="color: #000000;">6</span>
&nbsp;
Percentage of the requests served within a certain <span style="color: #000000; font-weight: bold;">time</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>ms<span style="color: #7a0874; font-weight: bold;">&#41;</span>
  <span style="color: #000000;">50</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">3</span>
  <span style="color: #000000;">66</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">3</span>
  <span style="color: #000000;">75</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">80</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">90</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">95</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">98</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
  <span style="color: #000000;">99</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">4</span>
 <span style="color: #000000;">100</span><span style="color: #000000; font-weight: bold;">%</span>      <span style="color: #000000;">6</span> <span style="color: #7a0874; font-weight: bold;">&#40;</span>longest request<span style="color: #7a0874; font-weight: bold;">&#41;</span></pre></div></div>

</p>
<p>
Тут даже говорить нечего, все сказано в первом и втором выводах ab2. Достаточно взглянуть хотя бы на параметр «Time taken for tests», который показывает общее время проведения тестов. В первом случае он равен  26.412 секунд, во втором - 0.337 секунд. Прирост производительности почти в 80 раз!
</p>
<p>
Конечно, тестирование на локальном компьютере — это не есть тестирование в условиях, приближенных к реальным, однако какое-то представление оно все же дает.
</p>
<p>
А теперь вернемся к примеру, который был описан в самом начале статьи. Есть страница с постоянным контентом и есть блок с последними комментариями.
</p>
<p>
Как кэширование, которое мы только что внедрили в Symfony, поможет нам с кэшированием такой страницы? Пока никак. Наш кэш живет только какое-то определенное время, указанное в параметре lifetime, поэтому блок с комментариями будет обновляться только, когда истечет время жизни кэша. Но нас это не устраивает, нужно, чтобы страница обновлялась каждый раз после того, как добавился комментарий. Хорошо бы после добавления комментария удалять из кэша страницу.
</p>
<p>
Зададимся вопросом: «В какой момент у нас обычно должен обновляться кэш?». Обычно в момент, когда что-то меняется в базе данных. При чем, если изменения производятся в таблице, где хранятся комментарии, то обновляться должны страницы, где выводятся блоки, связанные с комментариями.
</p>
<p>
Для начала подключим к нашему проекту на Symfony <strong>базу данных</strong>. Не имеет значения какую базу данных использовать. Если вы знакомы с Symfony, то без труда сможете подключить свою базу данных. В своих же примерах я использую <em>MySQL</em>, <em>пользователь root</em> с паролем secretpass, имя базы данных — symfony.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># mysqladmin -uroot -psecretpass create symfony</span>
<span style="color: #666666; font-style: italic;"># php symfony configure:database &quot;mysql:host=localhost;dbname=symfony&quot; root secretpass</span></pre></div></div>

</p>
<p>
Теперь опишем нашу будущую базу данных в Symfony, для этого отредактируем файл config/doctrine/schema.yml:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">Comment:
  columns:
    text: <span style="">&#123;</span> type: string<span style="">&#40;</span><span style="">255</span><span style="">&#41;</span>, notnull: true <span style="">&#125;</span></pre></div></div>

</p>
<p>
Далее воспользуемся готовыми инструментами Symfony и сгенерируем код для моделей, SQL для базы данных.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony doctrine:build --model</span>
<span style="color: #666666; font-style: italic;"># php symfony doctrine:build --sql</span>
<span style="color: #666666; font-style: italic;"># php symfony doctrine:insert-sql</span></pre></div></div>

</p>
<p>
Последняя команда выполняет SQL, чтобы создать необходимые <em>таблицы в базе данных</em>. Вместо этих трех команд можно было бы выполнить php symfony doctrine:build —all, которая выполняет те же 3 действия, но за один раз.
</p>
<p>
Теперь сгенерируем стандартную функциональность для добавления, удаления, редактирования и просмотра списка объектов модели:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony doctrine:generate-module --with-show --non-verbose-templates frontend comment Comment</span></pre></div></div>

</p>
<p>
Здесь мы говорим сгенерировать код для нового модуля comment, код генерируется для существующей модели Comment.
</p>
<p>
Далее необходимо переопределить метод save() для моделей, участвующих в кэшировании. У нас это одна модель Comment, поэтому открываем файл lib/model/doctrine/Comment.class.php и добавляем в класс Comment метод save():
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">class</span> Comment <span style="color: #000000; font-weight: bold;">extends</span> BaseComment
<span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">function</span> save<span style="color: #009900;">&#40;</span>Doctrine_Connection <span style="color: #000088;">$conn</span> <span style="color: #339933;">=</span> <span style="color: #009900; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        parent<span style="color: #339933;">::</span><span style="color: #004000;">save</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$conn</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        sfHtmlCacheFilter<span style="color: #339933;">::</span><span style="color: #004000;">deleteCache</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>

</p>
<p>
Мы добавили метод save(), который переопределяет метод save() класса <strong>Doctrine_Record</strong>. В нашем методе мы вызываем метод save() родительского класса, которым и окажется Doctrine_Record::save().
</p>
<p>
Далее вызывается метод нашего класса-фильтра sfHtmlCacheFilter::deleteCache($this), которому в качестве параметра передается сохраняемый объект. Таким образом, этот новый метод не делает ничего нового, кроме как добавляется метод для очистки кэша при каждом сохранении объекта.
</p>
<p>
Удаляем кэш Symfony, чтобы наши изменения вступили в силу.
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;"><span style="color: #666666; font-style: italic;"># php symfony cache:clear</span></pre></div></div>

</p>
<p>
Все, теперь зайдем по адресу http://localhost/comment и увидим сгенерированную Symfony страницу. Нажимаем на ссылку «New», добавляем первую запись, возвращаемся назад к списку и видим только что добавленный комментарий.
</p>
<p>
Выше уже упоминалось, что в конфиге html_cache.yml можно прописывать зависимости страниц от моделей. Пришло время рассказать об этом подробнее.<br />
Настройки в файле html_cache.yml используется следующим образом.
</p>
<p>
Перед отдачей любой страницы клиенту проверяется наличие адреса этой страницы в конфиге. Если он есть, то происходит запись содержимого страницы в кэш.<br />
При сохранении модели вызывается метод класса-фильтра для удаления из кэша страниц, зависящих от текущей модели. Модели перечислены, как элементы первого уровня, на втором уровне перечислены зависящие от этих моделей адреса страниц.
</p>
<p>
Сейчас у нас в файле html_cache.yml на первом уровне прописана несуществующая модель Index, на втором уровне прописана главная страница. Т. к. модели Index у нас нет, то эта настройка просто говорит о том, что неоходимо записывать в кэш содержимое главной страницы, но никакого удаления ее из кэша не происходит.
</p>
<p>
Для такой главной страницы это и не нужно, т. к. там выводится всегда одна и та же информация. А вот со страницей списка комментариев ситуация иная — если для нее мы применяем кэширование, то необходимо удалять кэш этой страницы при каждом добавлении комментария.
</p>
<p>
Добавим такую настройку. Страница со списком комментариев располагается по адресу http://localhost/comment. Добавляем в файл config/html_cache.yml следующую запись:
</p>
<p>
<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;">Comment:
  /comment: <span style="">&#123;</span> lifetime: <span style="">86400</span> <span style="">&#125;</span></pre></div></div>

</p>
<p>
Теперь наша страница  http://localhost/comment будет отдаваться клиенту еще на стороне nginx при наличии ее в кэше. В противном случае nginx передаст управление Symfony, который сформирует и запишет содержимое страницы в кэш.
</p>
<p>
Таким образом, мы организовали зависимость страниц от изменяющихся моделей — при изменении определенных моделей очищается кэш зависящих от этих моделей страниц.
</p>
<p>
В файле html_cache.yml можно использовать <strong>регулярные выражения</strong>, а также подставлять в адреса страниц результаты выполнения методов объектов. Применим кэширование к детальным страницам комментариев, которые располагаются по адресам вида - http://localhost/comment/show/id/1 .
</p>
<p>
Добавим к модели Comment следующую зависимость:
</p>
<div class="geshi_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
</pre>
</td>
<td class="code">
<pre class="ini" style="font-family:monospace;">Comment:
  /comment: <span style="">&#123;</span> lifetime: <span style="">86400</span> <span style="">&#125;</span><b>
  /comment/show/id/<span style="">&#40;</span>\d+<span style="">&#41;</span>: <span style="">&#123;</span> lifetime: <span style="">86400</span>, attributes: <span style="color: #000066; font-weight:bold;"><span style="">&#91;</span>Id<span style="">&#93;</span></span> <span style="">&#125;</span></pre>
<p></b></p>
</td>
</tr>
</table>
</div>
<p>
Здесь мы указали в адресе регулярное выражение, которое пропускает только числовые значения ID комментариев. Мы также указали новый параметр attributes, который является массивом. В этом массиве объявляются методы модели, возвращаемые значения которых будут подставлены по порядку вместо регулярных выражений, заключенных в скобки. Причем методы могут возвращать не только обычные значения, но и массивы, в этом случае для удаления из кэша будет сформирован массив адресов страниц.
</p>
<p>
В данном примере вместо регулярного выражения (\d+) будет подставлен результат вызова метода getId() для объекта модели Comment. Это справедливо только при сохранении объекта и <strong>удалении кэша</strong> для него. При добавлении страницы в кэш будет произведено лишь сравнение текущего адреса страницы с регулярным выражением /comment/show/id/(\d+) и, если адрес пройдет проверку, то страница добавится в кэш.
</p>
<p>
После произведенных изменений в файле html_cache.yml страницы вида  http://localhost/comment/show/id/1 постигнет участь предыдущих рассматриваемых страниц — они будут писаться в кэш.
</p>
<p>
Помимо параметров lifetime и attributes можно использовать параметр beforeDeleteCache, в который передается название метода модели (полное название). Этот метод должен возвращать true или false. При получении false кэш для записи с этим параметром удаляться не будет.
</p>
<p>
На этом все. Теперь наш проект на Symfony стал не просто быстрым, а мегабыстрым. Ответы клиент получает не от php-скриптов на сервере и даже не с диска, а из памяти сервера.
</p>
<p>
Спасибо за внимание! Чтобы ваши сайты всегда летали!
</p>
<p></p>
<p><b>UPD:</b> Спасибо Sergei за <a href="#350">найденную ошибку</a>. Все описанное работало только с латинскими буквами в url'е, но не работало с русскими. Внесены нужные изменения в класс-фильтр для Symfony, а также в конфиге nginx в качестве ключа для memcached теперь используется переменная $uri, а не $request_uri</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/300/feed</wfw:commentRss>
		<slash:comments>557</slash:comments>
		</item>
		<item>
		<title>Как я проводил собеседование</title>
		<link>http://job-interview.ru/articles/post/290</link>
		<comments>http://job-interview.ru/articles/post/290#comments</comments>
		<pubDate>Sun, 23 Jan 2011 17:44:01 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[вопросы]]></category>
		<category><![CDATA[задачи]]></category>
		<category><![CDATA[собеседование]]></category>

		<guid isPermaLink="false">/articles/post/290</guid>
		<description><![CDATA[Вот уже прошло почти полтора года, как я в поисках работы посещал собеседования в разных компаниях, после чего мною была написана статья Нужны ли логические задачи на собеседованиях?. И вот совсем недавно мне самому пришлось набирать команду программистов и проводить с ними собеседования. Как вы могли бы догадаться, собеседования без задач на логику.  
Так [...]]]></description>
			<content:encoded><![CDATA[<p>Вот уже прошло почти полтора года, как я в поисках работы посещал собеседования в разных компаниях, после чего мною была написана статья <a title="Нужны ли логические задачи на собеседованиях?" href="/articles/post/7">Нужны ли логические задачи на собеседованиях?</a>. И вот совсем недавно мне самому пришлось набирать команду программистов и проводить с ними собеседования. Как вы могли бы догадаться, собеседования без <strong>задач на логику</strong>. <img src='/articles/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>Так получилось, что через некоторое время в компании на проекте остался всего один программист — и это был я. Необходимо было в кратчайшие сроки воссоздать команду. <strong>Проведение собеседования</strong> доверили мне. </p>
<p>Цель: <em>найти 2-х программистов, один должен быть опытным, другой начинающим</em>.<br />
<span id="more-290"></span><br />
Хочу сразу сказать, эта статья не содержит никаких советов о том, как проводить «<strong>правильное собеседование</strong>». Здесь я рассказываю о своем опыте проведения собеседований и, как показало время, в моем случае эти собеседования оказались правильными, т.к. я подобрал тех людей, которых и хотел. Но обо всем по порядку.</p>
<p>Началось все с того, что в один прекрасный день ко мне утром подошел мой начальник и сказал, что через 20 минут должен придти соискатель и надо бы подготовить вопросы для него. 20 минут на подготовку вопросов!</p>
<p>Пришлось быстро вспомнить какие вопросы задавали мне на собеседованиях, поискать по интернету и т.д. В общем кое-как я подготовил 7 вопросов. 3 вопроса, на мой взгляд, были вообще элементарными, 2 — довольно простыми при наличии опыта, еще 2 — SQL-запросы, не из самых легких.</p>
<p>Итак, начали собеседование, я дал 15 минут на подготовку ответов на вопросы. По истечении этого времени кандидат дал 3 правильных ответа из 7 — 1 из категории элементарных, 2 из категории «простые при наличии опыта».</p>
<p>Такие ответы не давали полного понимания о знаниях человека. Вроде бы ответил на вопросы, которые должны были показать его опыт, но не ответил на 2 из 3-х элементарных вопросов. А что с SQL? Ответы были неправильными, но и вопросы не из легких.</p>
<p>Очевидно, что мною были неправильно подготовлены вопросы, они не позволяли понять знания кандидата. К слову сказать, в этот же день приходил еще один соискатель, с ним была примерно та же история — правильно ответил на 2 простых вопроса и 1 на проверку опыта.</p>
<p>Теперь мне нужно было подготовить правильные вопросы для проведения собеседования.  На следующий день должны были придти еще программисты, времени на подготовку вопросов было уже предостаточно.</p>
<p>Я решил, что все вопросы нужно разделить на несколько частей:</p>
<ol>
<li> <strong>Пара простейших вопросов, с которыми справится любой программист.</strong></li>
<p>Чтобы сразу же выявить тех, кто по своим знаниям нам точно не подходит. Должен сказать, что из всех собеседуемых таких оказалось 3 человека. С ними я сразу прощался, не переходя к более сложным вопросам.</p>
<li> <strong>Вопросы, на которые ответит любой программист с опытом.</strong></li>
<p>В общем-то это также несложные вопросы, но они показывают на сколько опытен программист. Например, человек, недавно окончивший университет и не работавший еще над более менее серьезными проектами, вряд ли будет знаком с различными <em>методами кэширования</em>, <em>системами контроля версий</em>, вряд ли он работал с <em>высоконагруженными проектами</em>.</p>
<li> <strong>Немного теории и вопросы по проектированию.</strong></li>
<p>Эта часть вопросов должна была показать на сколько человек способен работать самостоятельно, сможет ли он без тотального контроля решить задачу наиболее оптимальным способом. Сюда относятся составление правильной структуры БД еще до начала реализации, написание кода, который хорошо впишется в существующий. И не забываем про нагрузки — задача может быть реализована, прекрасно работать на девелоперских серверах, но после выката на продакшн может положить весь сайт.</p>
<li><strong>Несложные SQL-запросы.</strong></li>
<p>Ну и немного поломать мозг. Но только совсем слегка. Эта часть вопросов на составление <strong>SQL-запросов</strong>, все запросы довольно простые и при знании операторов SQL решаются быстро. Также здесь можно понять на сколько правильно человек выбирает методы решения — при незнании каких-то возможностей SQL, некоторые начинали составлять мегазапросы с огромным количеством подзапросов, join&#8217;ов и т.д.</p>
<li><strong>Вопросы не для всех.</strong></li>
<p>Эти вопросы я задавал только тем, кто с легкостью ответил на все предыдущие вопросы. Если они для соискателя очень простые, то хочется копнуть глубже и понять на сколько хороши его знания. Как правило, положительное решение по кандидатам, дошедших до этой части вопросов, у меня формировалось еще в середине собеседования.</ol>
<p>Первую версию вопросов я подготовил уже на следующий день. Вопросы готовил с той мыслью, что по окончании собеседования у меня должно быть четкое понимание готов ли я работать с этим человеком или нет, никаких сомнений быть не должно.</p>
<p>По началу после 1-2 собеседований я корректировал часть вопросов — некоторые вопросы были не понятны соискателям (криво составлены мной), некоторые я просто заменял, считая, что новые лучше подойдут для собеседования. В результате у меня сформировался список вопросов, с которым я ходил на каждое собеседование.</p>
<p>Для начала человек должен был ответить на 2 простых вопроса из 1-й части:</p>
<ol>
<li> <strong>jQuery</strong>
<ul>
<li>выбрать элементы с атрибутом id=&#8221;myID&#8221;</li>
<li>выбрать элементы с атрибутом class=&#8221;myClass&#8221;</li>
<li>выбрать все input&#8217;ы с атрибутом id=&#8221;myID&#8221;, которые находятся внутри &lt;div class=&#8221;myClass&#8221;&gt;</li>
</ul>
</li>
<li><strong>Javascript</strong>
<p>Необходимо выполнить команду alert(’!’) перед отправкой данных формы нажатием кнопки &#8220;ОК&#8221;.</p>
<p>Какой из перечисленных фрагментов кода позволит решить поставленную задачу?</p>
<ul>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;"> &lt;FORM ACTION=&quot;test.pl&quot; onSubmit=&quot;alert(’!’)&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;submit&quot; VALUE=&quot;OK&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;FORM ACTION=&quot;test.pl&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;button&quot; VALUE=&quot;OK&quot; onClick=&quot;alert(’!’);this.submit()&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;FORM ACTION=&quot;test.pl&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;submit&quot; VALUE=&quot;OK&quot; onSubmit=&quot;alert(’!’)&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
<li>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="html" style="font-family:monospace;">&lt;FORM ACTION=&quot;test.pl&quot; onBeforeSubmit=&quot;alert(’!’)&quot;&gt;
&lt;INPUT TYPE=&quot;text&quot; NAME=&quot;txt&quot;&gt;
&lt;INPUT TYPE=&quot;submit&quot; VALUE=&quot;OK&quot;&gt;
&lt;/FORM&gt;</pre></td></tr></table></div>

</li>
</ul>
</li>
<p>На эти вопросы, думаю, ответит каждый web-программист. Далее я переходил к следующей части вопросов, которые должны были показать на сколько человек опытен:</p>
<li> <strong>Memcached</strong>. Что это такое? В каких случаях применяется?</li>
<p>Здесь я также просил рассказать соискателя вообще о кэшировании: как устроена система кэширования? Что обычно кэшируют? Когда кэширование не применимо?</p>
<p>Подавляющее большинство было знакомо с кэшированием, но никогда не слышали про memcached, и рассказывали о хранении кэша в файлах. В основном соискатели использовали кэширование только результатов SQL-запросов.</p>
<li> Что такое <strong>паттерн проектирования singleton</strong> и как он реализуется?</li>
<p>Стандартный ответ на этот вопрос был такой: «Я слышал про singleton, применяется в ООП, но как реализуется и для чего нужен не помню». Примерно каждый 4-й полностью отвечал на этот вопрос.</p>
<li> Командная строка *nix. Напишите команду, которая убьет все процессы, начинающиеся на «proc».</li>
<p>Из всех кандидатов на этот вопрос правильно ответили 2 человека. В основном все сразу говорили, что с командной строкой не особо знакомы, знают несколько команд, но не более.</p>
<li> Зачем нужен <em>HAVING в SQL</em>?</li>
<p>Для меня это было удивительно, но на этот вопрос правильно ответили лишь человека 2-3. Когда я включал этот вопрос в свой список, у меня были сомнения нужен ли он вообще, но, как оказалось, очень даже нужен и показывает опыт работы с SQL.</p>
<p>После этого один вопрос на теорию, здесь же я пытался выяснить, как человек будет справляться с задачами проектирования.</p>
<li> Что такое <em>нормализация БД</em>? Что такое <em>денормализация БД</em>? Для чего она нужна?</li>
<p>Здесь пополам, кто-то отвечал, кто-то нет. Почти каждого, особенно тех, кто не помнил или не слышал этих слов, после этого вопроса я просил набросать структуру БД для хранения товаров интернет-магазина, у каждого товара может быть от одного и более разделов.</p>
<li> Расскажите о способах хранения <strong>деревьев в таблице</strong>? Например, когда нужно реализовать <strong>древовидные комментарии</strong> к статье.</li>
<p>Большинство отвечали стандартно — у каждого комментария есть поле parent_id и т.д. Некоторые были знакомы с различными методами хранения деревьев, а были люди, которые прямо на собеседовании придумывали эти методы.</p>
<p>Далее следовали вопросы по составлению запросов SQL. Я не задавал ни одного сложного запроса, все они были простые, для правильного ответа требовалось только знание SQL.</p>
<li>Имеется таблица пользователей следующей структуры:

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> users <span style="color: #66cc66;">&#40;</span> 
id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">,</span>
username CHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">16</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
city_id INT<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> 
<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<ul>
<li>id &#8211; целочисленный первичный ключ последовательной нумерации</li>
<li>username &#8211; логин пользователя</li>
<li>city_id &#8211; город проживания пользователя</li>
</ul>
<p>Необходимо выбрать города, в которых проживает не менее n пользователей</li>
<li>Имеется таблица для хранения информации о посещениях страниц пользователями:

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`page_visit`</span> <span style="color: #66cc66;">&#40;</span>
<span style="color: #ff0000;">`id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span><span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`user_id`</span> int<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`page`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">200</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #ff0000;">`date`</span> datetime <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span>  <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`id`</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #66cc66;">&#41;</span></pre></td></tr></table></div>

<p>Необходимо вывести:</p>
<ol type="a">
<li> последних 10 пользователей, посетивших страницу «/about/»</li>
<li> всех пользователей, посетивших страницу «/about/», с указанием следующих данных:
<ul type="square">
<li>ID пользователя</li>
<li>Количество посещений страницы</li>
<li>Время первого посещения страницы</li>
<li>Время последнего посещения страницы</li>
</ul>
</li>
</ol>
</li>
<li>Есть 2 таблицы:

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> users <span style="color: #66cc66;">&#40;</span>
id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span><span style="color: #66cc66;">,</span>
username CHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">16</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>
<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>


<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
</pre></td><td class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">CREATE</span> <span style="color: #993333; font-weight: bold;">TABLE</span> user_email <span style="color: #66cc66;">&#40;</span>
id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">AUTO_INCREMENT</span> <span style="color: #993333; font-weight: bold;">PRIMARY</span> <span style="color: #993333; font-weight: bold;">KEY</span> <span style="color: #66cc66;">,</span>
user_id INT<span style="color: #66cc66;">&#40;</span> <span style="color: #cc66cc;">11</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
email CHAR<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">16</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span>
<span style="color: #66cc66;">&#41;</span>;</pre></td></tr></table></div>

<p>Необходимо вывести все email&#8217;ы пользователей, а также их логины.</li>
<p>Далее был вопрос для тех, кто без особых проблем справился со всеми предыдущими:</p>
<li> Пользовались telnet? Напишите, как при при помощи telnet обратиться к главной странице example.com.</li>
<p>На этот вопрос ответил только один человек из всех соискателей. Кстати, он был сисадмином и решил переквалифицироваться в web-программиста.</ol>
<p>Для последней части, возможно, следовало бы придумать вопросов побольше, но у меня так и не дошли руки до этого, да и задавать их пришлось всего раза 2-3.</p>
<p>Помимо этих вопросов, некоторых соискателей по ходу собеседования я спрашивал о том, с какими <em>фреймворками</em> они работали, работали ли с <em>системами контроля версий</em> (<em>svn</em>, <em>cvs</em>, <em>git</em>), смогут ли настроить web-сервер (<em>nginx</em>, <em>apache</em>).</p>
<p>В итоге мне пришлось провести около 20-ти собеседований, после которых в нашу компанию были взяты на работу 2 программиста. Мне удалось выполнить поставленную цель: один программист — начинающий, сейчас он учится и растет каждый день  нереальными темпами, второй программист — уже поработавший в нашей профессии достаточно времени и в данный момент решает наши повседневные задачи самостоятельно и без чьей-либо помощи, он в ней и не нуждается.</p>
<p>На мой взгляд, все вопросы, которые я задавал, были довольно простыми. Я считаю, что не покажет человек в полной мере своих знаний, если его бомбить <strong>сложными вопросами на собеседовании</strong>.</p>
<p>Мне даже известны случаи, когда сложные вопросы только мешали правильному пониманию возможностей человека. Рассказывал один знакомый, который любит выносить мозг соискателю на собеседовании: к ним приходил человек, ответивший на очень сложный вопрос, вся их команда была удивлена этому факту. В итоге его взяли, а потом пришлось уволить, т.к. этот новый сотрудник начал просто разрушать их проекты своим качеством кода, неправильным подходом в самом начале задачи. Проще говоря, за ним нужен был глаз да глаз, что не входило в планы команды.</p>
<p>Простые вопросы сразу дают ответ, знает человек тот или иной вопрос или нет. Для ответа на сложные вопросы, как правило, необходимо обладать знаниями из разных областей, да еще надо пораскинуть мозгами и правильно применить эти знания — нет четкого понимания о знании или незнании конкретного вопроса, а это мешает правильно оценить человека.</p>
<p>Сложные вопросы требуют много времени на ответ, кроме того такими вопросами можно довести кандидата до того состояния, когда он уже не в готов ответить даже на то, что знает. Этим можно пропустить, возможно, неплохого программиста в будущем.</p>
<p>Итак, мой вывод: на <strong>собеседовании</strong> нужно задавать только <strong>простые вопросы</strong>, <strong>сложным вопросам</strong> тут не место. Этим я и руководствовался, общаясь с программистами, теперь по истечении времени я понимаю, что такое собеседование в моем случае оказалось правильным, т.к. своих целей я добился.</p>
<p>А что вы думаете о простых и сложных <strong>собеседованиях для программистов</strong>? Каким оно должно быть?</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/290/feed</wfw:commentRss>
		<slash:comments>193</slash:comments>
		</item>
		<item>
		<title>Хочу открыть интернет-магазин</title>
		<link>http://job-interview.ru/articles/post/271</link>
		<comments>http://job-interview.ru/articles/post/271#comments</comments>
		<pubDate>Sun, 30 May 2010 13:31:35 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Интернет-коммерция]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[интернет-магазин]]></category>
		<category><![CDATA[программирование]]></category>

		<guid isPermaLink="false">/articles/?p=271</guid>
		<description><![CDATA[
Наверное, многие, проработав определенное время в какой-то отрасли, приходят к мыслям о том, что нужно попробовать что-то свое. С некоторых пор такие мысли стали посещать и меня.


Я web-программист, проработал уже достаточное время на этой должности и, честно говоря, порядком подустал. К тому же я не вижу каких-то особых перспектив, к которым мне хотелось бы стремиться.


Нет, [...]]]></description>
			<content:encoded><![CDATA[<p>
Наверное, многие, проработав определенное время в какой-то отрасли, приходят к мыслям о том, что нужно попробовать что-то свое. С некоторых пор такие мысли стали посещать и меня.
</p>
<p>
Я <strong>web-программист</strong>, проработал уже достаточное время на этой должности и, честно говоря, порядком подустал. К тому же я не вижу каких-то особых перспектив, к которым мне хотелось бы стремиться.
</p>
<p>
Нет, они, конечно, есть. Программист перерастает в руководителя группы, потом в руководителя отдела, возможно, потом еще в кого-то, потом «потолок». Кого-то может такая ситуация устраивает, но она не для меня.
</p>
<p>
И я решил, что нужно открывать свое дело, где ты работаешь только на себя, получаешь столько денег, сколько заработал сам. Вот здесь открываются огромные перспективы. Они мне интересны, хочется стремиться к поставленным для себя целям.
</p>
<p>
Для начала я посоветовался со своими друзьями, перечитал не мало статей про различные  <a href="http://moyevro.ru/category/vidy-zarabotka/" title="виды заработка в интернете">виды заработка</a> для программиста. И вот какие выводы я для себя сделал:
</p>
<blockquote><p>
Где web-программист может проявить себя самостоятельно? </p>
<ul>
<li>
Фриланс.
</li>
<p>
Возможно, стоило бы попробовать, но все-таки по рассказам знакомых фрилансеров больших денег там не заработаешь. Особенно первое время придется усиленно экономить. Да и все же это не совсем работа на себя, а работа на заказчика.
</p>
<li>
Web-студия.
</li>
<p>
Для ее открытия нужен какой-то стартовый капитал, которого у меня нет. Кроме того, большие риски, что вложенные на начальном этапе средства так и не окупятся. Опять же в этом варианте присутствуют заказчики, на которых тебе придется вкалывать.
</p>
<li>
Интернет-магазин.
</li>
<p>На данный момент самый подходящий для меня вариант. Его я и выбрал.</p>
</ul>
</blockquote>
<p><span id="more-271"></span></p>
<h2>Почему я хочу открыть интернет-магазин?</h2>
<p>
<img style="padding: 10px" src="/img/shop_1.jpg" align="left" alt="Почему я хочу открыть интернет-магазин?" title="Почему я хочу открыть интернет-магазин?"><br />
Устал от работы на дядю, надоели начальники, которые вечно самоутверждаются за счет своих подчиненных.
</p>
<p>Ситуацию можно описать известной фразой: «Я начальник, ты дурак, ты начальник, я дурак». Причем как-то получается так, что «дураком» ты становишься автоматически, независимо от объема твоих знаний, опыта и т.д. Начальник все равно знает больше, чем ты, только он может принять единственно верные решения.</p>
<p>
Кто-то может сказать: «Все правильно, он прошел свой путь, начиная простым программистом, набрался опыта, поднялся по карьерной лестнице и, конечно же, он будет обладать большими знаниями».
</p>
<p>
Если он бывший программист, то да, я согласен. Однако, очень часто в роли начальников выступают совсем не программисты, а менеджеры, которые считают, что разбираются в твоей области гораздо лучше, чем ты, а все программисты — это обычные кодеры, которые реализовывают их гениальные идеи.
</p>
<p>
Найдется ли такой программист, который никогда не попадал на такой диалог?<br />
<em> &#8211; Сколько займет времени, чтобы это сделать?</em> <br />
<em> &#8211; Думаю, что где-то полдня нужно будет.</em> <br />
<em> &#8211; Почему так долго? Здесь же просто кнопку поставить.</em> 
</p>
<p>
Дальше ты начинаешь пытаться как-то объяснить, почему это занимает столько времени, но понимаешь, что то, что ты говоришь, человеку все равно не понятно. Да и занятие это бесполезное, но какой может быть другой выход, если тебе задают подобный вопрос.
</p>
<p>
В ответ на твои объяснения ты получаешь примерно следующую фразу: «<em>Ну не знаю, мне кажется, что все равно это очень долго</em>».
</p>
<p>
Кроме того, много денег при работе на кого-то не заработаешь. Все равно есть потолок.
</p>
<p>
Доход от интернет-магазина будет зависеть только от тебя и от его развития. Теоретически предела доходам здесь нет.
</p>
<p>
Еще одна причина, по которой я хочу начать свое дело — устал от работы в коллективе. Возможно, эта причина относится только ко мне, а может и нет.
</p>
<p>
На мой взгляд, каждому коллективу присуща определенная доля лживости. Вроде как все говорят: «Мы вместе, мы одна команда». Все друг другу улыбаются, все друзья, все классно. Однако, это только на поверхности.
</p>
<p>
Как люди могут быть друзьями, когда они всеми силами стараются показать себя выше других, чтобы начальство их заметило? А этим приходится заниматься, все ведь хотят продвинуться вверх по службе.
</p>
<p>
Коллективу часто приходится объяснять начальству, почему не выдерживаются сроки в том или ином проекте. А начальству важно знать, кто конкретно тормозит проект. В таких ситуациях приходится закладывать кого-то из своих «друзей».
</p>
<p>
Когда в коллективе решают, кому конкретно доверить очередной проект, тут то и выясняется, чьи знания и опыт ценят, а чьи нет.
</p>
<p>
Но ведь на поверхности то все равны, все сотрудники одинаково ценятся.
</p>
<p>
В общем эта как-бы «дружба» не для меня. Чисто с психологической точки зрения я бы себя чувствовал спокойнее, занимаясь своим делом и не отвлекаясь на всякие закулисные склоки.
</p>
<h2>А что продавать?</h2>
<p>
<img style="padding: 10px" src="/img/shop_2.jpg" align="right" alt="А что продавать?" title="А что продавать?"><br />
Вот это очень трудный и самый важный вопрос на начальном этапе. На данный момент в интернете можно купить почти все. Конкуренты есть везде. Но выбирать что-то нужно.
</p>
<p>Я для себя определил следующие критерии моего будущего товара:</p>
<ul>
<li>
Он должен быть легким, чтобы не было проблем при доставке.
</li>
<li>
Его стоимость не должна быть очень низкой. Большого объема заказов в первое время не предвидится, поэтому даже один заказ должен приносить более менее приличную сумму (не 1 рубль, а, скажем, 200).
</li>
<li>
Он должен быть приспособлен для интернета. Например, продавать продукты питания через интернет, на мой взгляд, не самая лучшая идея. Все-таки некоторые товары люди хотят «пощупать», когда его выбирают.
</li>
<li>
В идеале этот товар должен быть интересен мне, чтобы я мог иметь какое-то мнение по нему. Тогда я бы мог составлять описания к товарам, а это поможет продвижению в поисковиках.
</li>
</ul>
<p>
Осталось теперь найти товар, удовлетворяющий этим моим критериям. Пока я нахожусь в поиске.
</p>
<p>
Под эти пункты очень подходят книги, но здесь очень высока конкуренция, поэтому их я не рассматриваю.
</p>
<p>
<strong>Определиться с товаром</strong> — это одна проблема. Решив ее, придется еще <strong>найти поставщиков</strong>, которые готовы этот товар поставлять. Кроме того, т.к. у меня нет никакого <em>начального капитала</em>, то закупать товар оптом я не смогу. Поэтому нужно найти поставщика, который будет готов поставлять товар по факту заказа. Т.е. мне представляется следующая схема: мне пришел заказ, я еду к поставщику, забираю у него товар, доставляю товар клиенту.
</p>
<p>
Найти такого поставщика будет нелегкой задачей, но все же она должна быть решаема. Делаю такой вывод, основываясь на различные статьи в блогах, где люди на начальных стадиях сталкивались с такой проблемой и находили выход.
</p>
<p>
Итак, товар выбран, поставщик найден. Чем мой магазин будет отличаться от других? Нужно придумать <strong>уникальное торговое предложение</strong> (УТП). Возможно, в моем магазине цены будут ниже, чем у конкурентов, возможно, что-то еще, но клиента нужно будет чем-то зацепить, чтобы, совершив один раз покупку у меня, он вернулся ко мне же за следующей.
</p>
<p>
На эту тему я пока даже не думаю, сначала надо определиться с товаром.
</p>
<h2>Планы</h2>
<p>
<img style="padding: 10px" src="/img/shop_3.jpg" align="left" alt="Планы" title="Планы"><br />
Перед открытием магазина я <strong>зарегистрирую ИП</strong>. Скорее всего воспользуюсь услугами какого-нибудь агентства, но, похоже, что даже в этом случае придется помотаться по всяким гос. учреждениям. Ну а что делать, без этого в нашей стране никуда.
</p>
<p>
Еще думаю, что может сначала не писать навороченный магазин, а сделать просто <strong>список товаров</strong> и рядом номер телефона. Посмотрю, как пойдут заказы. Если будет все хорошо, то доработаю до приличного магазина.
</p>
<p>
С другой стороны, все говорят о <em>дружелюбном интерфейсе</em> для покупателей, что чуть ли это не самое главное. Ну в общем это я еще решу, просто не хотелось бы тратить время, если в итоге магазин не оправдает моих надежд.
</p>
<p>
Да, еще планирую обзавестись прямым номером на свой мобильный. Оставлять 10-значный номер телефона на сайте, как мне кажется, будет выглядеть не серьезно.
</p>
<p>
Доставкой буду заниматься первое время сам. Придется как-то совмещать с текущей работой, но это, надеюсь, продлится не долго, т.к. за первые 1-2 месяца станет более менее понятно, что получится из магазина в итоге.
</p>
<p>
Если заказов будет не мало, то возьму отпуск, может даже за свой счет.
</p>
<p>
Моя первоначальная цель — достичь дохода от магазина, равного половине моей текущей зарплаты. Если добьюсь этого, то планирую уволиться, а часть денег зарабатывать на <em>фрилансе</em>. В итоге мой месячный доход будет равен текущему доходу на постоянной работе.
</p>
<p>
Давно хочу изучить <em>язык программирования python</em> и <em>фреймворк django</em>. Как раз мой магазин поможет мне в этом. Даже, если ничего путного не выйдет, то, как минимум, будет опыт программирования на python.
</p>
<p>
Ну вот вроде и все. Я хотел в этой статье поделиться своими мыслями и планами по поводу открытия своего <strong>интернет-магазина</strong>. Как только приступлю к реализации этих планов, поделюсь полученным опытом в следующей статье.
</p>
<p>
Жду любых ваших мнений в комментариях.
</p>
<p>
Также интересно было бы узнать мнение программистов, которые уже прошли путь <strong>открытия своего бизнеса</strong> (не обязательно интернет-магазин).</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/271/feed</wfw:commentRss>
		<slash:comments>344</slash:comments>
		</item>
		<item>
		<title>CMS Битрикс. За и против.</title>
		<link>http://job-interview.ru/articles/post/234</link>
		<comments>http://job-interview.ru/articles/post/234#comments</comments>
		<pubDate>Thu, 04 Feb 2010 21:45:56 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[bitrix]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[битрикс]]></category>

		<guid isPermaLink="false">/articles/?p=234</guid>
		<description><![CDATA[Проработав 2 года с CMS Битрикс, у меня сформировалось свое отношение к этому движку. Есть как плюсы, так и минусы, но все же негатива накопилось гораздо больше.
В этой статье я поделюсь своим мнением с читателями и постараюсь описать и хорошие, и плохие стороны этой CMS.
Во-первых, хочется сказать пару слов о тормозах этой системы. В этом [...]]]></description>
			<content:encoded><![CDATA[<p>Проработав 2 года с <strong>CMS Битрикс</strong>, у меня сформировалось свое отношение к этому <em>движку.</em> Есть как плюсы, так и минусы, но все же негатива накопилось гораздо больше.</p>
<p>В этой статье я поделюсь своим мнением с читателями и постараюсь описать и хорошие, и плохие стороны этой <strong>CMS</strong>.</p>
<p>Во-первых, хочется сказать пару слов о <em>тормозах</em> этой системы. В этом ее любят обвинять очень многие.</p>
<p>Для простых сайтов движок вполне подходит и тормозов в этом случае наблюдаться не будет, если, конечно, <em>проектировщик</em> не допустил откровенных ляпов при создании структуры <strong>инфоблоков</strong> (о том что это за зверь сейчас узнаем).</p>
<p><span id="more-234"></span></p>
<p>Тормоза начинаются, когда от сайта требуется что-то большее, нежели обычный текстовый контент. В этом случае проектировщик сталкивается с неуклюжестью движка.<br />
В битриксе все основывается на понятии инфоблока. Давайте рассмотрим что же на самом деле из себя представляет <strong>инфоблок.</strong></p>
<p><img title="Диаграмма инфоблоков Битрикс" src="/uploads/tiger/bitrix.png" alt="Диаграмма инфоблоков Битрикс" /></p>
<p><strong>Инфоблок</strong> — это такая <em>сущность</em>, которая объединяет элементы с определенным набором свойств. Часть свойств, такие как название элемента, раздел, даты активности и т.п., присутствует у элементов всех инфоблоков. К этим свойствам проектировщик может добавить еще и свои свойства, но они уже будут рассматриваться в контексте каждого конкретного инфоблока.</p>
<p>Существует также понятие <strong>типа инфоблока</strong>, который объединяет в себе инфоблоки.<br />
Поясню на примере. Допустим, мы создаем сайт, на котором будут размещены <em>вакансии.</em>. В этом случае нам будут необходимы 3 инфоблока: «Вакансии», «Отрасли», «Компании».</p>
<p>После создания инфоблока «Вакансии» мы можем создать в нем элементы со стандартным набором свойств:</p>
<ul>
<li>Название</li>
<li>Активность (да/нет)</li>
<li>Период активности (активен в указанный период времени)</li>
<li>Краткое описание</li>
<li>Подробное описание</li>
<li>Изображение-превью</li>
<li>Увеличенное изображение</li>
<li>Раздел</li>
</ul>
<p>Этих свойств будет достаточно для обычного текстового контента (статьи, новости и т.д.), но нам для вакансий этого не хватит. Мы создадим еще свойства:</p>
<ul>
<li>Компания (свойство, ссылающееся на инфоблок «Компании»)</li>
<li>Отрасль (свойство, ссылающееся на инфоблок «Отрасли»)</li>
<li>Опыт работы (свойство типа список с значениями «до 2-х лет», «от 2-х до 4-х лет», «более 4 лет» и т.д.)</li>
</ul>
<p>В инфоблоке «Отрасли» и «Компании» ограничимся стандартным набором свойств, которые предоставляет нам битрикс.</p>
<p>Вот, что у нас получилось:</p>
<p><img title="Структура инфоблоков Битрикс для размещения вакансий" src="/uploads/tiger/vacancy_bitrix.png" alt="Структура инфоблоков Битрикс для размещения вакансий" /></p>
<p>Вроде бы с точки зрения <em>теории баз данных</em> у нас все верно. Все сущности разделены, избыточности нет и т.д. Но давайте взглянем на <strong>структуру базы</strong>.</p>
<p>Рассмотрим как работает <strong>выборка из инфоблоков</strong> на простом примере. В <strong>битриксе</strong> существует часть таблиц в базе данных, которые хранят данные, связанные с инфоблоками — сами инфоблоки (b_iblock), их элементы(b_iblock_element), свойства(b_iblock_property), значения свойств (b_iblock_element_property).</p>
<p>Это не все таблицы, связанные с инфоблоками, но для простоты понимания нас будут интересовать именно они.</p>
<p><img title="ER-диаграмма некоторых таблиц Битрикса, хранящих данные об инфоблоках" src="/uploads/tiger/bd_bitrix.png" alt="ER-диаграмма некоторых таблиц Битрикса, хранящих данные об инфоблоках" /></p>
<p>Как видим, элементы всех инфоблоков хранятся в одной таблице, все свойства этих элементов так же хранятся в одной таблице.</p>
<p>Как же так! Зачем <em>СУБД</em> копаться в вакансиях, отраслях, если нам нужно будет выбрать всего лишь список всех компаний, вакансии которых храняться в базе ?!</p>
<p>А что будет, если нашему сайту необходим более сложный функционал? Вот тогда то и начнутся тормоза.</p>
<p>Теперь воспользуемся <strong>АПИ битрикса</strong> и выберем список вакансий конкретной компании, но те вакансии, которые не относятся к определенной отрасли.</p>
<p>В примере происходит выборка из инфоблока «Вакансии», ID которого 23, а также происходит фильтрация по компании, ID которой 373, и по отрасли, ID которой 317. В последнем параметре метода GetList передается список выбираемых полей — ID, компания, опыт работы, начало периода активности вакансии.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$arFilter</span> <span style="color: #339933;">=</span> <span style="color: #990000;">Array</span><span style="color: #009900;">&#40;</span>
<span style="color: #0000ff;">&quot;IBLOCK_ID&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">23</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// выбираем элементы из инфоблока, ID которого 23</span>
<span style="color: #0000ff;">&quot;ACTIVE&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">&quot;Y&quot;</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// выбираем только активные элементы</span>
<span style="color: #0000ff;">&quot;PROPERTY_COMPANY&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">373</span><span style="color: #339933;">,</span> <span style="color: #666666; font-style: italic;">// вакансии будут принадлежать компании с ID=373</span>
<span style="color: #0000ff;">&quot;!PROPERTY_BRANCH&quot;</span> <span style="color: #339933;">=&gt;</span><span style="color: #cc66cc;">317</span> <span style="color: #666666; font-style: italic;">// вакансии, принадлежащие отрасли с ID=317, нас не интересуют</span>
<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$res</span> <span style="color: #339933;">=</span> CIBlockElement<span style="color: #339933;">::</span><span style="color: #004000;">GetList</span><span style="color: #009900;">&#40;</span><span style="color: #990000;">Array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;DATE_ACTIVE_FROM&quot;</span><span style="color: #339933;">=&gt;</span><span style="color: #0000ff;">&quot;ASC&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arFilter</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #339933;">,</span> <span style="color: #990000;">Array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;ID&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;PROPERTY_COMPANY&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;PROPERTY_EXPERIENCE&quot;</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;DATE_ACTIVE_FROM&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Выглядит красиво, прямо как-будто один безобидный <strong>SQL запрос</strong>, но заглянем внутрь:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">SELECT</span> BP<span style="color: #66cc66;">.*</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock_property BP<span style="color: #66cc66;">,</span> b_iblock B
<span style="color: #993333; font-weight: bold;">WHERE</span>
BP<span style="color: #66cc66;">.</span>IBLOCK_ID<span style="color: #66cc66;">=</span>B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">23</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> UPPER<span style="color: #66cc66;">&#40;</span>BP<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">=</span>UPPER<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'COMPANY'</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> BP<span style="color: #66cc66;">.*</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock_property BP<span style="color: #66cc66;">,</span> b_iblock B
<span style="color: #993333; font-weight: bold;">WHERE</span>
BP<span style="color: #66cc66;">.</span>IBLOCK_ID<span style="color: #66cc66;">=</span>B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">23</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> UPPER<span style="color: #66cc66;">&#40;</span>BP<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">=</span>UPPER<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'EXPERIENCE'</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> BP<span style="color: #66cc66;">.*</span>
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock_property BP<span style="color: #66cc66;">,</span> b_iblock B
<span style="color: #993333; font-weight: bold;">WHERE</span>
BP<span style="color: #66cc66;">.</span>IBLOCK_ID<span style="color: #66cc66;">=</span>B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">IN</span> <span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">23</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> UPPER<span style="color: #66cc66;">&#40;</span>BP<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">=</span>UPPER<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'BRANCH'</span><span style="color: #66cc66;">&#41;</span>
&nbsp;
<span style="color: #993333; font-weight: bold;">SELECT</span> BE<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> ID<span style="color: #66cc66;">,</span> FPV0<span style="color: #66cc66;">.</span>VALUE <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_COMPANY_VALUE<span style="color: #66cc66;">,</span> FPV0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_COMPANY_VALUE_ID<span style="color: #66cc66;">,</span> FPEN0<span style="color: #66cc66;">.</span>VALUE <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_EXPERIENCE_VALUE<span style="color: #66cc66;">,</span> FPEN0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_EXPERIENCE_ENUM_ID<span style="color: #66cc66;">,</span> FPV1<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AS</span> PROPERTY_EXPERIENCE_VALUE_ID<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">IF</span><span style="color: #66cc66;">&#40;</span>EXTRACT<span style="color: #66cc66;">&#40;</span>HOUR_SECOND
<span style="color: #993333; font-weight: bold;">FROM</span>
BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&gt;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y %H:%i:%s'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> DATE_ACTIVE_FROM<span style="color: #66cc66;">,</span><span style="color: #993333; font-weight: bold;">IF</span><span style="color: #66cc66;">&#40;</span>EXTRACT<span style="color: #66cc66;">&#40;</span>HOUR_SECOND
<span style="color: #993333; font-weight: bold;">FROM</span>
BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&gt;</span><span style="color: #cc66cc;">0</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y %H:%i:%s'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span> DATE_FORMAT<span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE_FROM<span style="color: #66cc66;">,</span> <span style="color: #ff0000;">'%d.%m.%Y'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AS</span> ACTIVE_FROM
<span style="color: #993333; font-weight: bold;">FROM</span>
b_iblock B
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_lang L <span style="color: #993333; font-weight: bold;">ON</span> B<span style="color: #66cc66;">.</span>LID<span style="color: #66cc66;">=</span>L<span style="color: #66cc66;">.</span>LID
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element BE <span style="color: #993333; font-weight: bold;">ON</span> BE<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property FP0 <span style="color: #993333; font-weight: bold;">ON</span> FP0<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FP0<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'COMPANY'</span>
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property FP1 <span style="color: #993333; font-weight: bold;">ON</span> FP1<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FP1<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'EXPERIENCE'</span>
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property FP2 <span style="color: #993333; font-weight: bold;">ON</span> FP2<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> B<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FP2<span style="color: #66cc66;">.</span>CODE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'BRANCH'</span>
<span style="color: #993333; font-weight: bold;">INNER</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element_property FPV0 <span style="color: #993333; font-weight: bold;">ON</span> FPV0<span style="color: #66cc66;">.</span>IBLOCK_PROPERTY_ID <span style="color: #66cc66;">=</span> FP0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV0<span style="color: #66cc66;">.</span>IBLOCK_ELEMENT_ID <span style="color: #66cc66;">=</span> BE<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element_property FPV1 <span style="color: #993333; font-weight: bold;">ON</span> FPV1<span style="color: #66cc66;">.</span>IBLOCK_PROPERTY_ID <span style="color: #66cc66;">=</span> FP1<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV1<span style="color: #66cc66;">.</span>IBLOCK_ELEMENT_ID <span style="color: #66cc66;">=</span> BE<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_element_property FPV2 <span style="color: #993333; font-weight: bold;">ON</span> FPV2<span style="color: #66cc66;">.</span>IBLOCK_PROPERTY_ID <span style="color: #66cc66;">=</span> FP2<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV2<span style="color: #66cc66;">.</span>IBLOCK_ELEMENT_ID <span style="color: #66cc66;">=</span> BE<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">LEFT</span> <span style="color: #993333; font-weight: bold;">JOIN</span> b_iblock_property_enum FPEN0 <span style="color: #993333; font-weight: bold;">ON</span> FPEN0<span style="color: #66cc66;">.</span>PROPERTY_ID <span style="color: #66cc66;">=</span> FP0<span style="color: #66cc66;">.</span>ID <span style="color: #993333; font-weight: bold;">AND</span> FPV1<span style="color: #66cc66;">.</span>VALUE_ENUM <span style="color: #66cc66;">=</span> FPEN0<span style="color: #66cc66;">.</span>ID
<span style="color: #993333; font-weight: bold;">WHERE</span>
<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>IBLOCK_ID <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'23'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>ACTIVE<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'Y'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>FPV0<span style="color: #66cc66;">.</span>VALUE_NUM <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'373'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span> FPV2<span style="color: #66cc66;">.</span>VALUE_NUM <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span> <span style="color: #993333; font-weight: bold;">OR</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #66cc66;">&#40;</span>FPV2<span style="color: #66cc66;">.</span>VALUE_NUM <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'317'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">AND</span> <span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#40;</span>BE<span style="color: #66cc66;">.</span>WF_STATUS_ID<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span> <span style="color: #993333; font-weight: bold;">AND</span> BE<span style="color: #66cc66;">.</span>WF_PARENT_ELEMENT_ID <span style="color: #993333; font-weight: bold;">IS</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
<span style="color: #993333; font-weight: bold;">ORDER</span> <span style="color: #993333; font-weight: bold;">BY</span>
BE<span style="color: #66cc66;">.</span>ACTIVE_FROM <span style="color: #993333; font-weight: bold;">ASC</span></pre></div></div>

<p>Ужас! А что же тогда творится с <em>СУБД</em> на реальных сайтах.</p>
<p>Мы при написании метода <strong>GetList</strong> использовали 3 свойства (ключи значений массивов, начинающиеся с «PROPERTY_») и в <strong>SQL-запросах</strong>, которые сгенерил битрикс, видим 3 запроса для каждого из 3-х свойств. А что будет, если создать десятки свойств? А будет ровно столько запросов сколько участвует в методе GetList.</p>
<p>Ну и в конце мы видим громадный запрос, напичканный join&#8217;ами. Если приглядеться к этому запросу, то можно догадаться, что количество join&#8217;ов зависит от количества свойств, участвующих в методе GetList.</p>
<p>Понятно, что все это плата за универсальность. Все те, кто используют <strong>битрикс</strong> любят повторять, что это далеко не идеальная система, но это лучшая CMS из всех существующих. А чем она лучше? Да только, пожалуй, тем, что у нее присутствует больше всевозможных модулей по сравнению с другими <strong>CMS</strong>. Еще есть удобная админка, в которой быстро разберутся модераторы. Так же битрикс постоянно обновляется и пополняется новыми модулями, в этом тоже его плюс.</p>
<p>Как я уже сказал, мое мнение, что битрикс сгодится только для простых сайтов. Если требуется какой-то более менее сложный функционал, то приходится ломать голову как обойти эти издержки универсальности.</p>
<p>Возникает вопрос. Зачем простому сайту, на котором в основном <em>статьи</em> и новости, дополнительные модули в виде магазина, форума, блогов, тормозной статистики (которую к тому же предлагают многие бесплатные сервисы). А ведь такой сайт <em>программист</em> может без проблем создать, например, на бесплатном <em>фреймворке symfony</em>, в котором админка генерится одной командой. Так зачем платить больше?</p>
<p>Ну а сайт со сложным функционалом, как я уже сказал, по моему мнению начинать делать на битриксе лучше не стоит. Эта затея перерастет в поиски путей обхода битриксовых фич.<br />
И все-таки смысл создавать сайты на битриксе, как мне видится, есть. Но прежде, чем описать свою точку зрения на этот счет, нужно сказать несколько слов о многочисленной армии кодеров-битриксоидов.</p>
<p>Это такие люди, в основном студенты, которые еще не слышали ни о теории баз данных, ни о паттернах проектирования, не работали с существующими фреймворками. Для них битрикс — это все, что стоит за сайтом. Они даже о новых <em>технологиях</em> узнают только тогда, когда она будет включена в очередную версию <em>CMS</em>.</p>
<p>Как-то раз ко мне подошел один из сотрудников за помощью. Он парсил <em>файл CSV</em>, но этот процесс у него отрабатывал не верно. Стали смотреть скрипт и тут программист высказывает свое предположение: «Может быть <strong>битрикс</strong> где-то закрался?». Может быть всемогущий битрикс каким-то  магическим образом и мог бы закрасться в его скрипт, но дело в том, что он его запускал без подключения движка. На самом деле потом нашли обычную ошибку в логике самого скрипта.</p>
<p>Еще был случай. Отмечали чей-то день рождения и двое программистов начали обсуждать все достоинства битрикса. Один из них кинул фразу: «Ну битрикс — это очень мощная система, он внутри себя и <em>язык Си</em> использует, и <em>ассемблер</em>». Второй округлил глаза и не поверил. А тот ему: «Ну ты залезь в код битрикса, посмотри». Тут вообще без комментариев.</p>
<p>Так вот, мое мнение, что создавать сайты на битриксе имеет смысл, но только для <em>менеджеров</em>. Они не знают всех тонкостей работы движка, его подводных камней.<br />
Им выгодно иметь в своем штате <strong>битриксоидов</strong>, которым не нужно платить нормальные деньги, ведь это еще новичек, который дальше битрикса ничего не видел. Да и работать он будет с системой, в которой уже большинство вещей сделано за него.</p>
<p>Таким образом, на свет появляются <em>web-студии</em>, которые штампуют на битриксе сайт за сайтом. Их основной задачей в итоге становиться увеличение штата сотрудников, способных делать сайты на битриксе. <em>Дешевая рабочая сила</em>. Чем больше штат, тем больше сайтов они смогут клепать.</p>
<p>И напоследок хотелось бы дать совет <strong>начинающим программистам</strong>. Не устраивайтесь на работу в <em>web-студии</em>, которые в своих описаниях вакансий упоминают слово «<strong>Битрикс</strong>». Если вы начнете свой карьерный путь с этого движка, то потом соскочить с него будет не просто. Пройдет года 2 и ваши друзья уже неплохо продвинуться в программировании, кто-то перерастет в <em>проектировщика</em>, а вы будете жить одними <strong>инфоблоками</strong> и не понимать что происходит внутри.<br />
Я сейчас не говорю о всех, но именно таких программистов я встречал часто. Конечно, все люди разные, кто-то может на работе использовать битрикс, но дома в целях <em>самообразования</em> тренироваться в других <em>областях программирования</em>. Но все же лучше набираться знаний на работе, где человек проводит большую часть своего времени.</p>
<p>На этом все. Спасибо за внимание. В комментариях жду ваших мыслей по поводу использования битрикса.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/234/feed</wfw:commentRss>
		<slash:comments>869</slash:comments>
		</item>
		<item>
		<title>“Многопоточность” в PHP (socket)</title>
		<link>http://job-interview.ru/articles/post/194</link>
		<comments>http://job-interview.ru/articles/post/194#comments</comments>
		<pubDate>Sun, 27 Dec 2009 13:21:34 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[socket]]></category>
		<category><![CDATA[асинхронные сокеты]]></category>
		<category><![CDATA[многопоточность]]></category>
		<category><![CDATA[неблокирующие сокеты]]></category>

		<guid isPermaLink="false">/articles/?p=194</guid>
		<description><![CDATA[Использование асинхронных сокетов.
Предлагаю вашему вниманию третью статью из цикла &#8220;Многопоточность&#8221; в  PHP. В данной статье мы рассмотрим асинхронные или неблокирующие сокеты.
Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у [...]]]></description>
			<content:encoded><![CDATA[<h3>Использование асинхронных сокетов.</h3>
<p>Предлагаю вашему вниманию третью статью из цикла <a href="/articles/post/62" target="_blank">&#8220;Многопоточность&#8221; в  PHP</a>. В данной статье мы рассмотрим <strong>асинхронные</strong> или <strong>неблокирующие сокеты</strong>.</p>
<p>Обычно, когда мы открываем несколько сокетов, мы делаем это последовательно, т.е. открываем соединение к одному, ждем завершения соединения, что-либо делаем, закрываем, открываем следующий и т.д. Налицо неудобство такого подхода, когда ресурсов для соединения у нас много и с ними производятся одинаковые действия. Хорошо, если бы можно было не дожидаться завершения соединения, а сразу же открывать следущее. И такая возможность существует.</p>
<p>Но сначала давайте разберем само <strong>понятие &#8220;сокет&#8221;</strong>. Что такое сокет?<br />
<span id="more-194"></span></p>
<blockquote><p><strong>Сокеты</strong>  — это название программного интерфейса для обеспечения информационного обмена между <em>процессами</em>. Процессы при таком обмене могут исполняться как на одном компьютере, так и на различных, связанных между собой сетью. <strong>Сокет</strong> — абстрактный объект, представляющий конечную точку соединения.</p></blockquote>
<p>В нашем случае сокет будет представлять собой соединение между нашей программой и компьютером, с которого требуется получить необходимую информацию.</p>
<p><em>Работа с сокетами</em> достаточно проста:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// создаем сокет</span>
<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// открываем сокет</span>
<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'80'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// записываем данные в сокет</span>
<span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #339933;">,</span> <span style="color: #990000;">strlen</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #666666; font-style: italic;">// читаем данные из сокета</span>
<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Сначала <em>функцией socket_create</em> инициализируем сокет и задаем его характеристики – флаг AF_INET, переданный в качестве первого параметра, указывает, что создается  сокет для интернета, второй параметр – тип сокета (самые распространенные – TCP и UDP)  нам нужен TCP-сокет &#8211; SOCK_STREAM, и третий параметр задает протокол (TCP).<br />
Затем с помощью <em>функции socket_connect</em> происходит соединение к указанному адресу и порту. Надо заметить, что эта функция принимает в качестве параметра не сам адрес хоста, а его ip адрес, поэтому сначала мы должны его определить <em>функцией gethostbyname</em>.<br />
Теперь нам надо <strong>сформировать запрос</strong>, который мы отправим на сервер (подробнее о <strong>http-заголовках</strong> можно почитать в <a href="/articles/post/86" target="_blank">статье PHP и HTTP</a>). Собственно отправку производит <em>функция socket_write</em>, второй параметр которой – это то, что мы отправляем и третий – длина отправляемой строки (т.е. всех сформированных заголовков).<br />
Запись произведена, теперь <em>функцией socket_read</em> читаем данные, переданные для нас сервером.<br />
В результате в переменной $result хранится хтмл, который нам необходим.</p>
<p>Задача у нас стоит та же, что и в предыдущих примерах: <em>получить содержимое нескольких html-страниц</em>. Вот код, реализующий это:</p>

<div class="wp_syntax"><table><tr><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
</pre></td><td class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">&lt;?php</span>
<span style="color: #666666; font-style: italic;">// страницы, содержимое которых надо получить</span>
<span style="color: #000088;">$urls</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'www.yandex.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.google.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.mail.ru'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'www.rambler.ru'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #000088;">$rtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи чтения</span>
<span style="color: #000088;">$wtasks</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// задачи записи</span>
<span style="color: #000088;">$results</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// результаты</span>
&nbsp;
<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$urls</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// открываем отдельный сокет</span>
	<span style="color: #000088;">$sh</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_create</span><span style="color: #009900;">&#40;</span>AF_INET<span style="color: #339933;">,</span> SOCK_STREAM<span style="color: #339933;">,</span> SOL_TCP<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// таймаут для чтения</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_RCVTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// таймаут для записи</span>
	<span style="color: #990000;">socket_set_option</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> SOL_SOCKET<span style="color: #339933;">,</span> SO_SNDTIMEO<span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;sec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">10</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">&quot;usec&quot;</span> <span style="color: #339933;">=&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// задаем неблокирующий режим сокетов</span>
	<span style="color: #990000;">socket_set_nonblock</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// определяем ip хоста</span>
	<span style="color: #000088;">$ip</span> <span style="color: #339933;">=</span> <span style="color: #990000;">gethostbyname</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// соединяемся</span>
	<span style="color: #990000;">socket_connect</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$ip</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">80</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// добавляем в задачи для записи</span>
	<span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #666666; font-style: italic;">// продолжаем, пока есть задачи для записи или чтения</span>
<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span> <span style="color: #339933;">||</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью чтения</span>
	<span style="color: #000088;">$rtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$rtasks</span><span style="color: #339933;">;</span>
	<span style="color: #666666; font-style: italic;">// массив для сокетов с возможностью записи</span>
	<span style="color: #000088;">$wtasks_</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$wtasks</span><span style="color: #339933;">;</span>
&nbsp;
	<span style="color: #666666; font-style: italic;">// ждем результатов из сокетов</span>
	<span style="color: #000088;">$n</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_select</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks_</span><span style="color: #339933;">,</span> <span style="color: #000088;">$e</span><span style="color: #339933;">=</span><span style="color: #009900; font-weight: bold;">null</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">10</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
	<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$n</span> <span style="color: #339933;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для записи</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач записи</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач записи</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$wtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// добавляем в задачи чтения</span>
			<span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$sh</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// формируем http-заголовки</span>
			<span style="color: #000088;">$headers</span>  <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;GET / HTTP/1.0<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Host: &quot;</span><span style="color: #339933;">.</span><span style="color: #000088;">$url</span><span style="color: #339933;">.</span><span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.6) Gecko/2009011913 MRA 5.3 (build 02557) Firefox/3.0.6<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Language: ru,en-us;q=0.7,en;q=0.3<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
			<span style="color: #000088;">$headers</span> <span style="color: #339933;">.=</span> <span style="color: #0000ff;">&quot;<span style="color: #000099; font-weight: bold;">\r</span><span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">;</span>
&nbsp;
			<span style="color: #666666; font-style: italic;">// записываем в сокет</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #990000;">socket_write</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$headers</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">===</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span> <span style="color: #990000;">fclose</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
&nbsp;
		<span style="color: #666666; font-style: italic;">// сокеты, доступные для чтения</span>
		<span style="color: #b1b100;">foreach</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks_</span> <span style="color: #b1b100;">as</span> <span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
			<span style="color: #666666; font-style: italic;">// ищем урл страницы по дескриптору сокета в массиве задач чтения</span>
			<span style="color: #000088;">$url</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array_search</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#41;</span> <span style="color: #b1b100;">continue</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// считываем результат из сокета</span>
			<span style="color: #000088;">$result</span> <span style="color: #339933;">=</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">;</span>
			<span style="color: #b1b100;">while</span> <span style="color: #009900;">&#40;</span><span style="color: #000088;">$r</span> <span style="color: #339933;">=</span> <span style="color: #990000;">socket_read</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #339933;">,</span> <span style="color: #cc66cc;">1024</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #000088;">$result</span> <span style="color: #339933;">.=</span> <span style="color: #000088;">$r</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// закрываем сокет</span>
			<span style="color: #990000;">socket_close</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$sh</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// удаляем из задач чтения</span>
			<span style="color: #990000;">unset</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$rtasks</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
			<span style="color: #666666; font-style: italic;">// заносим html в массив результатов</span>
			<span style="color: #000088;">$results</span><span style="color: #009900;">&#91;</span><span style="color: #000088;">$url</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">=</span> <span style="color: #000088;">$result</span><span style="color: #339933;">;</span>
		<span style="color: #009900;">&#125;</span>
	<span style="color: #009900;">&#125;</span>
	<span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
		<span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
	<span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">?&gt;</span></pre></td></tr></table></div>

<p>Можно заметить, что код несильно отличается от <a href="/articles/post/92#stream_code" target="_blank">кода для stream-функций</a>.</p>
<p>В общих словах здесь происходит следующее. Каждый сокет <em>инициализируется</em> и переводится в <em>неблокирующий режим</em>. Затем в цикле производится проверка готовых к чтению или записи сокетов, и если такие существуют, производится соответствующая операция. Все действия протекают в <em>асинхронном порядке</em>, т.е не ждут окончания предыдущей операции. Например, если данные с мэйл.ру поступили раньше, чем от яндекса, то будут обрабатываться именно они, хотя коннект к яндексу мог произойти до коннекта к мэйлу. Можно сказать, что все происходит в несколько &#8220;потоков&#8221;, когда параллельно ожидается готовность каждого сокета к какому-либо действию.</p>
<p>Теперь разберем код более подробно.<br />
Итак, у нас есть массив с адресами страниц. В строке 9 запускается цикл для инициализации соединения с каждым хостом. В 11 строке создается сокет, затем в 15 и 17 строках мы задаем таймауты для чтения и записи соответственно. В 19 строчке <em>функцией socket_set_nonblock</em> задаем <strong>неблокирующий режим,</strong> превращающий каждый наш сокет в <strong>асинхронный</strong>. Это необходимо для того, чтобы после очередной операции над сокетом не происходило ожидание ее окончания, а продолжал работу остальной код программы. В 26 строке заносим инициализированный сокет в массив сокетов для записи.</p>
<p>Основной цикл начинается в 30 строчке. Он будет продолжаться до тех пор, пока у нас остаются сокеты, в которые нужно записать или из которых надо прочитать.<br />
В 32 строке массиву $rtasks_ присваиваем массив сокетов, из которых должна быть прочитана информация. В 34-ой в $wtasks_ заносится массив с сокетами, в которые необходимо произвести запись.<br />
Главная функция в этом цикле &#8211; <em>socket_select</em>. Она принимает на вход массивы сокетов, ожидающих чтения, ожидающих запись и массив для исключительных ситуаций, четвертый параметр, передаваемый в данную функцию – таймаут. Параметры-массивы передаются по ссылке, т.е когда произойдет ожидаемое событие (<em>socket_select</em> в этом случае вернет число больше 0), в них появятся соответствующие дескрипторы.<br />
Если нашлись сокеты, доступные для записи, ищем урл, соответствующий каждому из готовых сокетов, и <em>функцией socket_write</em> записываем в него заголовки для получения хтмл страницы в ответе. Так же в 44-ой строке удаляем дескриптор из массива для записи, так как она будет произведена, и заносим его в строке 46 в массив для чтения, чтобы потом получить интересующий нас ответ.<br />
Если же имеются сокеты, готовые нам ответить, считываем из них информацию <em>функцией socket_read</em>.<br />
Profit! В массиве $results содержится вожделенный хтмл-код!</p>
<p><b>Замечание:</b><br />
<i>При вызове функции socket_connect, когда сокет переведен в неблокирующий режим функцией socket_set_nonblock, выдается предупреждение <b style="color: red;">&#8220;Operation now in progress&#8221; (&#8221;Операция на незаблокированном сокете не может быть завершена немедленно&#8221;)</b>, а socket_connect возвращает false. Несмотря на это, код нормально отрабатывает.</i></p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/194/feed</wfw:commentRss>
		<slash:comments>12549</slash:comments>
		</item>
		<item>
		<title>Отладка программ в командной строке Linux</title>
		<link>http://job-interview.ru/articles/post/160</link>
		<comments>http://job-interview.ru/articles/post/160#comments</comments>
		<pubDate>Sat, 31 Oct 2009 18:08:33 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[отладка]]></category>
		<category><![CDATA[программирование]]></category>
		<category><![CDATA[язык C]]></category>

		<guid isPermaLink="false">/articles/?p=160</guid>
		<description><![CDATA[
Как известно, все программисты при написании программ допускают ошибки. Не думаю, что найдется хоть один разработчик, который,как-то решив разработать более-менее сложное приложение, сел за свой компьютер, открыл любимый редактор, набрал нужный код, скомпоновал его и после запуска программа сделала все то, что от нее требовалось.


Все это из области фантастики. Каждый из нас допускает ошибки, поэтому [...]]]></description>
			<content:encoded><![CDATA[<p>
Как известно, все <em>программисты</em> при написании программ допускают ошибки. Не думаю, что найдется хоть один разработчик, который,как-то решив разработать более-менее сложное приложение, сел за свой компьютер, открыл любимый редактор, набрал нужный код, скомпоновал его и после запуска программа сделала все то, что от нее требовалось.
</p>
<p><a target="_blank" href="http://6.joinru.programmerinfo.e-autopay.com/"><img src="/img/courses/C++bannergif.gif"></a></p>
<p>Все это из области фантастики. Каждый из нас допускает ошибки, поэтому нам нужно их как-то отлавливать. </p>
<p>Если <em>ошибка синтаксическая</em>, то  в большинстве случаев на это укажет компилятор. Но, если  <strong>ошибка логическая</strong>, то часто <em>программист</em> сам не в состоянии определить ее.</p>
<p>Конечно, если <em>программа</em> не сложная, то можно самостоятельно, не прибегая ни к каким дополнительным средствам, выявить ошибку.</p>
<p>Однако, в больших программах самостоятельно отследить тот момент, когда программа начинает вести себя неправильно в большинстве случаев просто невозможно. В таких ситуациях на помощь приходят <strong>отладчики</strong>, которые позволяют программисту пройти по пути работы программы, отслеживая при этом ее состояние в определенные моменты времени выполнения.</p>
<p>В этой статье рассказывается об <strong>отладке программ</strong>, написанных на языке C, в <em>командной строке Linux</em> с использованием утилиты <strong>GDB</strong>.</p>
<p><span id="more-160"></span></p>
<p>Многие программисты, которые с успехом разрабатывали свои приложения на <strong>языках C/C++</strong> для <em>Windows</em>, после перехода к разработке программ на том же языке, но под ОС семейства <em>Linux</em> с удивлением обнаруживают, что отсутствует возможность той отладки, которой они пользовались в редакторах при написании программ для <em>Windows</em>.</p>
<p>Однако, такая возможность есть и это <strong>отладчик GDB</strong>.</p>
<p>Как следует из документации к этой утилите «<em>цель отладчика GDB</em>  &#8211; это позволить вам увидеть, что происходит внутри программы пока она выполняется, или что программа делает в момент ее краха.».</p>
<p>На момент написания этой статьи <strong>отладчик GDB</strong> работает с программами, написанными на <em>языках C, C++, Modula-2</em>. Мы будем отлаживать приложение, написанное на <strong>языке C</strong>.</p>
<p>Давайте начнем с приведения кода программы, которая в качестве аргумента принимает число и высчитывает <em>факториал</em> этого числа при помощи <em>рекурсии</em>. Ее мы и будем отлаживать.</p>
<p><div class="wp_syntax">
<table>
<tr>
<td class="line_numbers">
<pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre>
</td>
<td class="code">
<pre class="c" style="font-family:monospace;"><span style="color: #339933;">#include &lt;stdio.h&gt;</span>
<span style="color: #339933;">#include &lt;stdlib.h&gt;</span>
<span style="color: #339933;">#include &lt;unistd.h&gt;</span>
&nbsp;
<span style="color: #993333;">int</span> fact<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> num<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>num <span style="color: #339933;">&lt;=</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#123;</span>
      <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">1</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #b1b100;">return</span> num <span style="color: #339933;">*</span> fact<span style="color: #009900;">&#40;</span>num <span style="color: #339933;">-</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
&nbsp;
<span style="color: #993333;">int</span> main<span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> argc<span style="color: #339933;">,</span> <span style="color: #993333;">char</span> <span style="color: #339933;">**</span>argv<span style="color: #009900;">&#41;</span>
<span style="color: #009900;">&#123;</span>
  <span style="color: #993333;">int</span> a <span style="color: #339933;">=</span> atoi<span style="color: #009900;">&#40;</span>argv<span style="color: #009900;">&#91;</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #000066;">printf</span><span style="color: #009900;">&#40;</span><span style="color: #ff0000;">&quot;%d! = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span><span style="color: #339933;">,</span> a<span style="color: #339933;">,</span> fact<span style="color: #009900;">&#40;</span>a<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
  <span style="color: #b1b100;">return</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre>
</td>
</tr>
</table>
</div>
<p>Теперь скомпилируем ее с включением отладочной информации. Для этого в командной строке заходим в директорию, в которой лежит наш файл с расширением .c и выполняем команду:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">g++</span> <span style="color: #660033;">-g</span> fact.c <span style="color: #660033;">-o</span> fact</pre>
</div>
</div>
<p>Опция <em>-g</em> сообщает <em>компилятору</em> о том, что в программу нужно включить отладочную информацию, которой и воспользуется <strong>отладчик GDB</strong>. </p>
<p>Опция <em>-o</em> сообщает <strong>компилятору g++</strong> путь до исполняемого файла. Если ее не указать, то, по умолчанию, компилятор создаст исполняемый файл в той же директории, где находится наша программа, и назовет его a.out.</p>
<p>Теперь запустим нашу программу в режиме отладки:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #c20cb9; font-weight: bold;">gdb</span> <span style="color: #660033;">-q</span> fact</pre>
</div>
</div>
<p>Опцию <em>-q</em> можно не указывать, она используется лишь для того, чтобы при первом заходе в отладчик не выводилась информация о версии, лицензионное соглашение и т.д.</p>
<p>Итак, мы запустили отладчик. Теперь мы можем выполнять его команды.</p>
<p>Для просмотра исходного кода программы используется команда <em>list</em>, в которую можно передать номер строки для того, чтобы вывести код, окружающий переданную строку. </p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> list <span style="color: #000000;">10</span>
<span style="color: #000000;">5</span>       int fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>int num<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">6</span>       <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">8</span>           <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">9</span>             <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">1</span>;
<span style="color: #000000;">10</span>          <span style="color: #7a0874; font-weight: bold;">&#125;</span>
<span style="color: #000000;">11</span>
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">13</span>      <span style="color: #7a0874; font-weight: bold;">&#125;</span></pre>
</div>
</div>
<p>Также можно передать название функции, после чего будет выведен код, окружающий эту функцию.</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> list fact
<span style="color: #000000;">1</span>       <span style="color: #666666; font-style: italic;">#include &lt;stdio.h&gt;</span>
<span style="color: #000000;">2</span>       <span style="color: #666666; font-style: italic;">#include &lt;stdlib.h&gt;</span>
<span style="color: #000000;">3</span>       <span style="color: #666666; font-style: italic;">#include &lt;unistd.h&gt;</span>
<span style="color: #000000;">4</span>
<span style="color: #000000;">5</span>       int fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>int num<span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">6</span>       <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">8</span>           <span style="color: #7a0874; font-weight: bold;">&#123;</span>
<span style="color: #000000;">9</span>             <span style="color: #7a0874; font-weight: bold;">return</span> <span style="color: #000000;">1</span>;
<span style="color: #000000;">10</span>          <span style="color: #7a0874; font-weight: bold;">&#125;</span></pre>
</div>
</div>
<p>Давайте запустим теперь <strong>выполнение программы под отладчиком</strong>. Это можно сделать одной из двух команд: <em>run</em> или <em>start</em>.</p>
<p>Отличие между этими двумя командами в том, что, вызвав команду <em>start</em>, отладчик останавливается на входе в функцию main, а команда <em>run</em> выполняется до тех пор, пока не наткнется на <strong>точку останова</strong> (о них чуть позднее).</p>
<p>Обе эти команды принимают в качестве параметра аргументы программы так же, как если бы программа запускалась из командной строки.</p>
<p>Итак, запустим программу на выполнение в режиме отладки:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> start <span style="color: #000000;">4</span>
Temporary breakpoint <span style="color: #000000;">2</span> at 0x8048556: <span style="color: #c20cb9; font-weight: bold;">file</span> fact.c, line 17.
Temporary breakpoint <span style="color: #000000;">2</span>, main <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">argc</span>=<span style="color: #000000;">2</span>, <span style="color: #007800;">argv</span>=0xbffffa24<span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">17</span>
<span style="color: #000000;">17</span>        int a = atoi<span style="color: #7a0874; font-weight: bold;">&#40;</span>argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;</pre>
</div>
</div>
<p>Как видим, отладчик остановился сразу же на входе в функцию main, а также вывел код и номер строки, перед которой остановился.</p>
<p>Используя команду <em>print</em>, мы можем вывести значения переменных и выражений. Посмотрим какие входные аргументы приняла наша программа:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> print argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">0</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
$<span style="color: #000000;">1</span> = 0xbffffb41 <span style="color: #ff0000;">&quot;/home/user/cpp/fact&quot;</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> print argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span>
$<span style="color: #000000;">2</span> = 0xbffffb5f <span style="color: #ff0000;">&quot;4&quot;</span></pre>
</div>
</div>
<p>В нулевом элементе массива argv содержится путь до выполняемой программы, а в первом элементе наш переданный аргумент — 4.</p>
<p>Для того, чтобы перейти на следующую строку, необходимо выполнить команду <em>step</em> или <em>next</em>.</p>
<p>Используя эти команды, можно передвигаться по программе. Отличие этих команд состоит в том, что <em>step</em> будет заходить внутрь функции каждый раз, когда ее встретит, а <em>next</em> пойдет дальше.</p>
<p>Перейдем к следующей строке:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">18</span>        <span style="color: #7a0874; font-weight: bold;">printf</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;%d! = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, a, fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>a<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;</pre>
</div>
</div>
<p>Мы сделали один шаг и остановились перед 18-ой строкой.</p>
<p>Пойдем дальше:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
fact <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">num</span>=<span style="color: #000000;">4</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">7</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span></pre>
</div>
</div>
<p>Мы вошли в функцию fact с входным параметром 4 и оказались перед 7-ой строкой.</p>
<p>Т.к. мы имеем дело с рекурсией, то, вероятно, нам будет интересно значение переменной num, которое будет изменяться при каждом рекурсивном входе в функцию fact.</p>
<p>Добавим в процесс отладки слежение за переменной num. Для этого существует команда <em>display</em>, которой необходимо передать название переменной. В нашем случае это будет переменная num.</p>
<p>Выполним команду <em>display</em> и перейдем на один шаг вперед:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> display num
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">4</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">4</span></pre>
</div>
</div>
<p>Как видим, теперь при каждой остановке программы <strong>отладчик GDB</strong> сообщает нам значение переменной num.</p>
<p>Сейчас мы находимся перед рекурсивным входом в функцию fact. Заходим в нее и делаем еще один шаг вперед:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
fact <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">num</span>=<span style="color: #000000;">3</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">7</span>
<span style="color: #000000;">7</span>           <span style="color: #000000; font-weight: bold;">if</span><span style="color: #7a0874; font-weight: bold;">&#40;</span>num <span style="color: #000000; font-weight: bold;">&lt;</span>= <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">3</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">3</span></pre>
</div>
</div>
<p>Отладчик сообщает нам значение переменной num, которое уже равно 3. Сейчас мы снова находимся перед заходом в функцию fact. </p>
<p>Скорее всего, не имеет смысла каждый раз проделывать эти шаги в функции fact. Нам достаточно было бы отслеживать какие значения принимает переменная num в 12-ой строке, т.к. в этой строке происходит рекурсивный вызов функции, а также возвращается результат ее выполнения.</p>
<p>Для того, чтобы добиться поставленных целей, мы можем поставить <strong>точки останова</strong>. Наша рассматриваемая программа достаточно не велика, поэтому мы могли бы пройти по каждой строке, используя отладчик, вплоть до завершения программы.</p>
<p>Однако, в реальных программах <em>программисты</em> отлаживают код, который содержит в себе тысячи строк. Если бы для отладки такого кода пришлось бы обойти каждую строку, то это превратилось бы в долгую и муторную работу.</p>
<p>Расставив <strong>точки останова</strong>, отладчик может «перепрыгивать» к строкам, на которых они поставлены, минуя весь остальной код. Для этого можно использовать команду <em>continue</em>, которая продолжает выполнение программы до тех пор, пока не встретится <strong>точка останова</strong>. Если их нет, то программа выполнится до конца.</p>
<p>Итак, давайте поставим точку останова в строке 12 и выполним команду <em>continue</em>, чтобы продолжить программу до тех пор, пока не наткнемся на строку 12:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">break</span> <span style="color: #000000;">12</span>
Breakpoint <span style="color: #000000;">2</span> at 0x8048529: <span style="color: #c20cb9; font-weight: bold;">file</span> fact.c, line 12.
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">continue</span>
Continuing.
&nbsp;
Breakpoint <span style="color: #000000;">2</span>, fact <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">num</span>=<span style="color: #000000;">2</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">12</span>
<span style="color: #000000;">12</span>          <span style="color: #7a0874; font-weight: bold;">return</span> num <span style="color: #000000; font-weight: bold;">*</span> fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>num - <span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #000000;">1</span>: num = <span style="color: #000000;">2</span></pre>
</div>
</div>
<p>Мы прошли все шаги, которые до этого проделывали командой <em>step</em>. Теперь, каждый раз выполняя команду <em>continue</em> мы будем оказываться на 12-ой строке, а, благодаря выполненной ранее команде <em>display</em>, мы сможем наблюдать как изменяется значение переменной num на каждом шаге.</p>
<p>Есть и другой способ следить за изменением переменной в ходе работы программы с использованием команды <em>watch</em>. В отличие от команды <em>display</em>, эта команда при каждом изменении переменной, переданной в качестве параметра, будет останавливать выполнение программы и выводить старое и новое значение переменной.</p>
<p>Обе команды <em>display</em> и <em>watch</em> могут в качестве параметра принимать не только переменные, но и выражения.</p>
<p>Продолжим выполнение программы:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;"><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #7a0874; font-weight: bold;">continue</span>
Continuing.
<span style="color: #000000;">4</span><span style="color: #000000; font-weight: bold;">!</span> = <span style="color: #000000;">24</span>
&nbsp;
Program exited normally.</pre>
</div>
</div>
<p>Отладчик показал вывод нашей программы, а именно подсчитанный факториал от 4. Последняя строка в выводе отладчика сообщает, что программа завершилась. Отладчик также вывел бы код возврата программы в восьмеричной форме, если бы программа возвращала число, отличное от нуля.</p>
<p>Очень полезной может оказаться команда <em>set variable</em>, которая позволяет изменять значение переменной по ходу выполнения программы:</p>
<p>
<div class="wp_syntax">
<div class="code">
<pre class="bash" style="font-family:monospace;">user<span style="color: #000000; font-weight: bold;">@</span>linux-hn2z:~<span style="color: #000000; font-weight: bold;">/</span>cpp<span style="color: #000000; font-weight: bold;">/&gt;</span> <span style="color: #c20cb9; font-weight: bold;">gdb</span> <span style="color: #660033;">-q</span> fact
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> start <span style="color: #000000;">4</span>
Temporary breakpoint <span style="color: #000000;">1</span> at 0x8048556: <span style="color: #c20cb9; font-weight: bold;">file</span> fact.c, line 17.
Starting program: <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>user<span style="color: #000000; font-weight: bold;">/</span>cpp<span style="color: #000000; font-weight: bold;">/</span>fact <span style="color: #000000;">4</span>
&nbsp;
Temporary breakpoint <span style="color: #000000;">1</span>, main <span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #007800;">argc</span>=<span style="color: #000000;">2</span>, <span style="color: #007800;">argv</span>=0xbfffef84<span style="color: #7a0874; font-weight: bold;">&#41;</span> at fact.c:<span style="color: #000000;">17</span>
<span style="color: #000000;">17</span>        int a = atoi<span style="color: #7a0874; font-weight: bold;">&#40;</span>argv<span style="color: #7a0874; font-weight: bold;">&#91;</span><span style="color: #000000;">1</span><span style="color: #7a0874; font-weight: bold;">&#93;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> step
<span style="color: #000000;">18</span>        <span style="color: #7a0874; font-weight: bold;">printf</span><span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #ff0000;">&quot;%d! = %d<span style="color: #000099; font-weight: bold;">\n</span>&quot;</span>, a, fact<span style="color: #7a0874; font-weight: bold;">&#40;</span>a<span style="color: #7a0874; font-weight: bold;">&#41;</span><span style="color: #7a0874; font-weight: bold;">&#41;</span>;
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> <span style="color: #000000; font-weight: bold;">set</span> variable <span style="color: #007800;">a</span>=<span style="color: #000000;">10</span>
<span style="color: #7a0874; font-weight: bold;">&#40;</span><span style="color: #c20cb9; font-weight: bold;">gdb</span><span style="color: #7a0874; font-weight: bold;">&#41;</span> c
Continuing.
<span style="color: #000000;">10</span><span style="color: #000000; font-weight: bold;">!</span> = <span style="color: #000000;">3628800</span></pre>
</div>
</div>
<p>В этом примере мы запустили программу с входным параметром — 4, но по ходу выполнения программы мы заменили этот параметр на 10, и программа подсчитала факториал от 10.</p>
<p>Команду <em>set variable</em> можно применять, например, когда вы на каком-то шаге обнаружили, что программа ведет себя не верно, но путем изменения значения переменной можно исправить ситуацию и посмотреть как программа будет вести себя дальше.</p>
<p>В настоящей статье описаны далеко не все <strong>возможности отладчика GDB</strong>. За более подробными руководствами обращайтесь к документации по утилите, кроме того, находясь в отладчике, можно вывести список всех команд и описаний к ним, воспользовавшись командой <em>help</em>.</p>
<p>На этом все. Удачной отладки.</p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/160/feed</wfw:commentRss>
		<slash:comments>634</slash:comments>
		</item>
		<item>
		<title>Вопросы на собеседовании для PHP-программиста (часть 3)</title>
		<link>http://job-interview.ru/articles/post/104</link>
		<comments>http://job-interview.ru/articles/post/104#comments</comments>
		<pubDate>Sat, 01 Aug 2009 17:49:23 +0000</pubDate>
		<dc:creator></dc:creator>
				<category><![CDATA[Собеседования]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[регулярные выражения]]></category>
		<category><![CDATA[собеседование]]></category>

		<guid isPermaLink="false">/articles/?p=104</guid>
		<description><![CDATA[Это заключительная статья, о вопросах на собеседованиях для PHP-программиста, на которые мне приходилось отвечать.
В первых двух статьях я уже выкладывал список вопросов.
В первой статье были вопросы по темам:

PHP
Задачи по составлению различных запросов SQL

В второй статье были вопросы по темам:

Администрирование MySQL
Основные принципы ООП

В этой статье я выкладываю вопросы с собеседований для PHP — программиста по следующим [...]]]></description>
			<content:encoded><![CDATA[<p>Это заключительная статья, о <strong>вопросах на собеседованиях</strong> для PHP-программиста, на которые мне приходилось отвечать.</p>
<p>В первых двух статьях я уже выкладывал список вопросов.</p>
<p>В первой <a title="Вопросы на собеседовании для PHP-программиста (часть 1)" href="/articles/post/12">статье</a> были вопросы по темам:</p>
<ul>
<li><em>PHP</em></li>
<li><em>Задачи по составлению различных запросов SQL</em></li>
</ul>
<p>В второй <a title="Вопросы на собеседовании для PHP-программиста (часть 2)" href="/articles/post/57">статье</a> были вопросы по темам:</p>
<ul>
<li><em>Администрирование MySQL</em></li>
<li><em>Основные принципы ООП</em></li>
</ul>
<p>В этой статье я выкладываю вопросы с собеседований для <strong>PHP — программиста</strong> по следующим темам:</p>
<ul>
<li><em>Регулярные выражения</em></li>
<li><em>Основные протоколы интернета</em></li>
<li><em>Работа в командной строке Linux</em></li>
</ul>
<p>Итак, представляю список вопросов.</p>
<h3>Регулярные выражения</h3>
<blockquote>
<ol>
<li>Напишите регулярное выражение для проверки E-mail.</li>
<li>С использованием регулярных выражений напишите скрипт, который в заданном тексте ищет все слова, начинающиеся на «Str», и переворачивает эти слова. На выходе скрипта должен быть текст с перевернутыми словами.</li>
<li>Напишите регулярное выражение, которое ищет все ссылки в документе HTML.</li>
</ol>
</blockquote>
<h3>Основные протоколы интернета</h3>
<blockquote>
<ol>
<li>По какому протоколу передаются данные в интернете?</li>
<li>Назовите <em>уровни модели OSI</em>.</li>
<li>В чем основные отличия протокола HTTP/1.1 от HTTP 1.0 ?</li>
<li>Что такое заголовки <em>HTTP</em>?</li>
<li>В чем состоит преимущество постоянных соединений?</li>
<li>Какие методы запроса протокола HTTP вы знаете?</li>
</ol>
</blockquote>
<h3>Работа в командной строке Linux</h3>
<blockquote>
<ol>
<li>Напишите команду, которая убьет все процессы, начинающиеся на «proc».</li>
<li>Напишите команду, которая поставит папке и всем папкам и файлам, которые в ней хранятся права: чтение, запись, выполнение для владельца, чтение, запись для группы, выполнение для всех остальных.</li>
<li>Какими средствами будете пользоваться, если нужно отслеживать запросы к web-серверу в реальном времени?</li>
</ol>
</blockquote>
<p>
На этом все. Надеюсь мой список вопросов поможет кому-то подготовиться к прохождению собеседования на должность PHP-программиста.
</p>
<p><a title="Вопросы на собеседовании для PHP-программиста (часть 1)" href="/articles/post/12">Вопросы на собеседовании для PHP-программиста (часть 1)</a></p>
<p><a title="Вопросы на собеседовании для PHP-программиста (часть 2)" href="/articles/post/57">Вопросы на собеседовании для php-программиста (часть 2)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://job-interview.ru/articles/post/104/feed</wfw:commentRss>
		<slash:comments>448</slash:comments>
		</item>
	</channel>
</rss>
