{
    "version": "https:\/\/jsonfeed.org\/version\/1.1",
    "title": "Блог Ильи Бирмана: заметки с тегом ПХП",
    "_rss_description": "Блог Ильи Бирмана о дизайне, городах, музыке и жизни.",
    "_rss_language": "ru",
    "_itunes_email": "ilyabirman@ilyabirman.ru",
    "_itunes_categories_xml": "<itunes:category text=\"Arts\"><itunes:category text=\"Design\" \/><\/itunes:category>\r\n<itunes:category text=\"Society &amp; Culture\"><itunes:category text=\"Personal Journals\" \/><\/itunes:category>\r\n<itunes:category text=\"Technology\" \/>\r\n",
    "_itunes_image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/userpic\/userpic-square@2x.jpg?1573933764",
    "_itunes_explicit": "no",
    "home_page_url": "https:\/\/ilyabirman.ru\/meanwhile\/tags\/php\/",
    "feed_url": "https:\/\/ilyabirman.ru\/meanwhile\/tags\/php\/json\/",
    "icon": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/userpic\/userpic@2x.jpg?1573933764",
    "authors": [
        {
            "name": "Илья Бирман",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/",
            "avatar": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/userpic\/userpic@2x.jpg?1573933764"
        }
    ],
    "items": [
        {
            "id": "6194",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/dollar-not-only-end\/",
            "title": "Доллар в регвыражениях не всегда означает конец строки",
            "content_html": "<p>Долго боролся сейчас с одним багом, поэтому пишу себе, чтобы не забыть.<\/p>\n<p>Есть регулярное выражение (для примера):<\/p>\n<blockquote>\n<p><tt>\/(some|any)thing$\/i<\/tt><\/p>\n<\/blockquote>\n<p>Доллар, уверен я, означает «конец строки». Выражение должно проверять, что строка заканчивается на слово something или anything в любом регистре. Но вот оно иногда срабатывает, даже если строка не заканчивается на него! Я в отчаянии уже проверяю впрямую, что строка заканчивается на g или G, и точно вижу, что она не заканчивается. А выражение срабатывает!<\/p>\n<p>Замечаю, что это происходит, если в конце выражения стоит возврат каретки. Думаю: какого хрена? У меня же написан доллар сразу после g, никаких возвратов каретки там! Модификатора \/m, который разделяет текст на отдельные строки, нет. Может, он как-то там по умолчанию включился, и надо его, наоборот, отключить?<\/p>\n<p>От безысходности <a href=\"https:\/\/www.php.net\/manual\/en\/reference.pcre.pattern.modifiers.php\">иду читать документацию<\/a>. Никакого антонима модификатору \/m не нахожу. Читаю про сам \/m:<\/p>\n<blockquote>\n<p><tt>m (PCRE_MULTILINE)<\/tt><br \/>\nBy default, PCRE treats the subject string as consisting of a single «line» of characters (even if it actually contains several newlines). The «start of line» metacharacter (^) matches only at the start of the string, while the «end of line» metacharacter ($) matches only at the end of the string, or before a terminating newline (unless D modifier is set).<\/p>\n<\/blockquote>\n<p>Что? Что ещё за нахрен \/D?<\/p>\n<blockquote>\n<p><tt> D (PCRE_DOLLAR_ENDONLY)<\/tt><br \/>\nIf this modifier is set, a dollar metacharacter in the pattern matches only at the end of the subject string. Without this modifier, a dollar also matches immediately before the final character if it is a newline (but not before any other newlines).<\/p>\n<\/blockquote>\n<p>Как же можно было такую дичь придумать? Исправляю регулярное выражение:<\/p>\n<blockquote>\n<p><tt>\/(some|any)thing$\/iD<\/tt><\/p>\n<\/blockquote>\n<p>А также запоминаю, что надо теперь вообще всегда использовать модификатор \/D, потому что если блин мне надо возврат каретки мэтчить, я это в состоянии впрямую сформулировать внутри регвыражения, а не полагаться на это хитрожопое исключение.<\/p>\n",
            "summary": "Долго боролся сейчас с одним багом, поэтому пишу себе, чтобы не забыть",
            "date_published": "2024-01-03T19:08:26+05:00",
            "date_modified": "2024-01-03T19:11:32+05:00",
            "tags": [
                "программирование",
                "ПХП"
            ],
            "_date_published_rfc2822": "Wed, 03 Jan 2024 19:08:26 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "6194",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "5062",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/php-nonempty-text-check-2\/",
            "title": "Проверка непустоты текста в ПХП: программисты пишут",
            "content_html": "<p>Недавно я писал о <a href=\"https:\/\/ilyabirman.ru\/meanwhile\/all\/php-nonempty-text-check\/\">проверке непустоты текста в ПХП<\/a>. Конечно, суровые программисты подняли меня на смех: да если у тебя код так написан, что ты не знаешь, какого типа у тебя переменная, то чего от тебя вообще ждать. Стоит отметить, что среди моих знакомых есть несколько очень сильных программистов. Разумеется, никому из них не пришло в голову высказываться в подобном ключе. Крутые программисты знают, что нет смысла критиковать решение, пока не знаешь подробности задачи.<\/p>\n<p>Напомню, я предложил проверять так:<\/p>\n<pre class=\"e2-text-code\"><code>if ((string) @$text !== '') { ... }<\/code><\/pre><p>Мне понесли варианты. «Специально для этого есть функция <tt>empty ()<\/tt>»:<\/p>\n<h2>1<\/h2>\n<pre class=\"e2-text-code\"><code>if (!empty ($text)) { ... }<\/code><\/pre><p>Это код с ошибкой: для <tt>(int) 0<\/tt> проверка будет пройдена.<\/p>\n<h2>2<\/h2>\n<pre class=\"e2-text-code\"><code>if (trim ($text) !== '') { ... }<\/code><\/pre><p>Это код с двумя ошибками: если переменная <tt>$text<\/tt> не определена, выведется предупреждение; если текст состоит из пробелов, проверка не будет пройдена.<\/p>\n<h2>3<\/h2>\n<pre class=\"e2-text-code\"><code>if (isset ($text) &amp;&amp; trim ($text)) { ... }<\/code><\/pre><p>В этом коде исправлена только первая ошибка предыдущего.<\/p>\n<p>Кстати, этот код полагается на «ленивое» вычисление логических выражений в ПХП: если просто поменять операнды конъюнкции местами, код снова станет с двумя ошибками. Само по себе это окей, но странно, когда такое предлагают программисты, борющиеся за чистоту кода.<\/p>\n<h2>4<\/h2>\n<pre class=\"e2-text-code\"><code>if (isset ($text) &amp;&amp; ($text !== &quot;&quot;)) { ... }<\/code><\/pre><p>Это длинный и мусорный код, и снова с ошибкой: и для <tt>false<\/tt>, и для <tt>NULL<\/tt> проверка будет пройдена.<\/p>\n<h2>5<\/h2>\n<pre class=\"e2-text-code\"><code>if (isset ($text) &amp;&amp; (string) $text !== '') { ... }<\/code><\/pre><p>Этот код — длинная и мусорная версия моего. В нём просто соблюдён религиозный ритуал «не использовать оператор <tt>@<\/tt>», ну и он дополнительно полагается на ленивое вычисление логики.<\/p>\n<p>Интересно, что никто из советчиков не указал на ошибку в моём исходном варианте (я её увидел сам, пока смотрел на предложенные альтернативы): если в переменную попадёт массив, проверка сработает, потому, что <tt>(string)<\/tt> от любого массива — это <tt>&quot;Array&quot;<\/tt>. В зависимости от того, что дальше делать с этой переменной, это может привести к проблемам. В этом удлинённом варианте ошибка та же.<\/p>\n<h2>6<\/h2>\n<p>Все варианты кода с оператором <tt>??<\/tt> — с фатальной ошибкой: такого оператора нет в ПХП 5.4, на котором должна работать Эгея.<\/p>\n<h2>7<\/h2>\n<pre class=\"e2-text-code\"><code>if (@strlen ($text)) { ... }<\/code><\/pre><p>Этот код работает правильно.<\/p>\n<p>Неприятность в том, что глядя на него нельзя этого сказать с уверенностью. Нужно читать документацию. Оказывается, у <tt>strlen ()<\/tt> есть полезная особенность: если передать ему массив, он вернёт 0, а вовсе не 5 (<tt>&quot;Array&quot;<\/tt>). Правда, это только начиная с ПХП 5.2, хе-хе. В документации не сказано, как он ведёт с себя с переменными других типов, поэтому нужно идти дальше и читать документацию по неявному преобразованию типов, чтобы узнать, что <tt>strlen (0)<\/tt> вернёт 1, как мне и требуется. Полагаться на такие штуки, когда ожидаешь какого-то чёткого и тонкого поведения, как-то некомфортно.<\/p>\n<p>Поэтому я пока оставил свой вариант, забив на потенциальную проблему с <tt>&quot;Array&quot;<\/tt>.<\/p>\n",
            "summary": "Недавно я писал о проверке непустоты текста в ПХП. Конечно, суровые программисты подняли меня на смех",
            "date_published": "2019-06-27T14:00:18+05:00",
            "date_modified": "2019-06-28T13:03:11+05:00",
            "tags": [
                "программирование",
                "ПХП"
            ],
            "_date_published_rfc2822": "Thu, 27 Jun 2019 14:00:18 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5062",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "5051",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/php-nonempty-text-check\/",
            "title": "Проверка непустоты текста в ПХП",
            "content_html": "<p>Только не бомбите, я для себя.<\/p>\n<p>В ПХП оператор <tt>==<\/tt> проверяет равенство значений безотносительно типа. Поэтому строка «42» и число 42 с его точки зрения равны.<\/p>\n<p>Это удобно: в большинстве случаев не нужно вообще думать о типах, просто сорок два равно сорока двум. Аналогично равны, например и логическая истина и число 1. Когда важно, чтобы значения были не просто равны, но ещё и совпадали по типу, используется оператор строгого равенства <tt>===<\/tt> .<\/p>\n<p>Часто важно убедиться, что переменная не пуста. Можно проверить так:<\/p>\n<pre class=\"e2-text-code\"><code>if (@$text) { ... }<\/code><\/pre><p>Как бы «если текст есть, то». Любая непустая строка приведётся к логически истине, при этом и пустая строка, и <tt>null<\/tt>, и даже неопределённая переменная приведутся ко лжи, и условие не выполнится.<\/p>\n<p>Но есть нюанс. Число 0 тоже приводится к логической лжи. С этим был связан баг в Эгее: если текст заметки состоят целиком из нуля, заметку не получалось сохранить, потому что до одной из таких строчек этот текст доходил в виде числа, и условие не выполнялось. А это вполне легальный текст заметки.<\/p>\n<p>У меня рука не поднимется исправить так:<\/p>\n<pre class=\"e2-text-code\"><code>if (@$text or $text === 0) { ... }<\/code><\/pre><p>Поэтому теперь я проверяю наличие текста так:<\/p>\n<pre class=\"e2-text-code\"><code>if ((string) @$text !== '') { ... }<\/code><\/pre><p>Не так элегантно, как было, но вроде жить можно. Или нет?<\/p>\n<p><a href=\"https:\/\/ilyabirman.ru\/meanwhile\/all\/php-nonempty-text-check-2\/\">Продолжение<\/a><\/p>\n",
            "summary": "Только не бомбите, я для себя",
            "date_published": "2019-06-14T18:47:47+05:00",
            "date_modified": "2019-06-27T14:03:14+05:00",
            "tags": [
                "вопрос",
                "программирование",
                "ПХП"
            ],
            "_date_published_rfc2822": "Fri, 14 Jun 2019 18:47:47 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "5051",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "4415",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/vopros-pro-fonovuyu-rabotu-php\/",
            "title": "Вопрос про фоновую работу ПХП",
            "content_html": "<p>Эгея написана на ПХП как обычное веб-приложение, отвечающее на запросы браузера к серверу. Браузер просит страницу — Эгея её генерирует и отдаёт.<\/p>\n<p>Часть работы, которую делает Эгея — медленная по своей природе, например создание бекапа или индексация большого блога для поиска. Но Эгея отдаёт страницы быстро.<\/p>\n<p>Это потому что в Эгее реализован механизм фоновой работы через запрос к себе. Когда нужно сделать что-то долгое, Эгея устанавливает ХТТП-соединение сама с собой, как бы делая вид, что она браузер, отправляет запрос по специальному урлу, который означает «сделай бекап» или «поиндексируй поиск», и тут же обрывает соединение. В результате выполнение скрипта заканчивается быстро, а вся долгая работа делается незаметно, как раз в ответ на этот запрос к себе. О таком методе я узнал лет двенадцать назад от Романа Иванова, и с тех пор пользуюсь.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/selfrequest@2x.png\" width=\"575\" height=\"300\" alt=\"Асинхронное выполнение на ПХП\" \/>\n<\/div>\n<p>К сожалению, с этим методом возникла проблема, когда я стал поддерживать ХТТПС. Если просто отправлять запрос и сразу закрывать соединение, как я всегда делал, не происходит вообще ничего — с точки зрения сервера всё выглядит так, как будто к нему и не обращались. Если же попробовать прочитать ответ, то приходит 400 Bad Request, потому что я как бы пытаюсь говорить с ХТТПС-сервером на простом ХТТП. К сожалению, мне почему-то так и не удалось отправить самому себе запрос по ХТТПС с помощью функции <tt>fsockopen ()<\/tt> и её родственников, хотя я вроде бы исчитал документацию со всех сторон.<\/p>\n<p>Вместо запроса к себе можно использовать <tt>register_shutdown_function ()<\/tt>. Но я когда-то пользовался ей, и у меня осталось ощущение ненадёжности — кажется, она выполнялась не всегда, и там были какие-то особенности внутри странные, например, что все пути к файлам должны быть указаны абсолютно. Короче, чтобы ей воспользоваться, нужно переструктурировать код. Женя Степанищев ещё рассказал про <tt>fastcgi_finish_request ()<\/tt> — похожий вариант.<\/p>\n<p>Эти схемы мне не нравятся непрозрачностью: часть скрипта будет выполняться в каком-то мире, который не виден никому. В варианте с запросом к себе мне ничто не мешает зайти браузером по моему служебному урлу и посмотреть, что происходит. А тут придётся что-то специальное изобретать для отладки. Кроме того, запрос к себе, разумеется, запускает новую копию ПХП, в которой заново начинается отсчёт времени. Выполняя такой запрос, я могу теоретически захотеть сделать что-то ещё так же, и инициировать запрос третьго уровня. И все эти запросы — одинаковой природы, просто заход по урлу. Мне нравится эта однородность.<\/p>\n<p>Есть радикальный вариант — переделать всё так, чтобы по служебным урлам ходил аджаксом клиент, пока ни о чём не подозревающий пользователь смотрит на уже загрузившуюся страницу. Такая конфигурация мне не нравится уже эстетически. Что это за беспомощный сервер, что ему надо, чтобы его клиент приводил в чувство? Возможно, это бред, но я бы хотел, чтобы сервер мог работать самостоятельно.<\/p>\n<p>Ну и пока умники в твиттере не начали писать «расскажите кто-нибудь Бирману про крон», объясню, что моя задача — сделать максимально автономное решение, не требующее от пользователя никакой специальной настройки сервера. Закачал на сервер папку — всё работает. Если вы матёрый программист в свитере, вам такое не понять.<\/p>\n<p>Короче, в идеале я бы хотел заставить работать свою исходную конфигурацию. Для этого мне нужно научиться делать запрос к себе по ХТТПС. Причём мне нужно просто «потрогать» нужный урл и отвалиться — мне не нужно по нему передавать никаких данных, не нужно читать ответ. Как это сделать?<\/p>\n<p>Ну и если вы знаете какой-то ещё способ добиться нужного результата, лишённый всех описанных недостатков, тоже расскажите.<\/p>\n",
            "summary": "Эгея написана на ПХП как обычное веб-приложение, отвечающее на запросы браузера к серверу. Браузер просит страницу — Эгея её генерирует и отдаёт",
            "date_published": "2017-05-24T00:06:27+05:00",
            "date_modified": "2017-05-25T15:14:30+05:00",
            "tags": [
                "веб-разработка",
                "вопрос",
                "ПХП",
                "Эгея"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/selfrequest@2x.png",
            "_date_published_rfc2822": "Wed, 24 May 2017 00:06:27 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4415",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/selfrequest@2x.png",
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg"
                ]
            }
        },
        {
            "id": "4321",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/php-art\/",
            "title": "ПХП-арт",
            "content_html": "<p>Пока я в декабре делал всякие <a href=\"http:\/\/ilyabirman.ru\/meanwhile\/all\/website-news-2017-jan\/\">апдейты на этом сайте<\/a>, у меня вылезло такое:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/php-art.jpg\" width=\"1024\" height=\"1173\" alt=\"ПХП-арт\" \/>\n<\/div>\n<p>Это ПХП-арт.<\/p>\n",
            "summary": "Пока я в декабре делал всякие апдейты на этом сайте, у меня вылезло такое",
            "date_published": "2017-02-13T00:06:05+05:00",
            "date_modified": "2017-02-13T00:05:45+05:00",
            "tags": [
                "ПХП",
                "скриншоты"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/php-art.jpg",
            "_date_published_rfc2822": "Mon, 13 Feb 2017 00:06:05 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "4321",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/php-art.jpg"
                ]
            }
        },
        {
            "id": "2997",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/weekend-reading-19\/",
            "title": "Что почитать на выходных — 19",
            "content_html": "<p>Например:<\/p>\n<ol start=\"1\">\n  <li><a href=\"http:\/\/grosslarnakh.livejournal.com\/27307.html\">Как интерфейс без обратной агрессии вызывает в людях ярость<\/a>. Очередной кайфовый Людвиг. Подписывайтесь на него уже, если ещё не, нельзя же в каждый список его включать.<\/li>\n  <li><a href=\"http:\/\/www.codinghorror.com\/blog\/2012\/06\/concluding-the-great-mp3-bitrate-experiment.html\">Concluding the Great MP3 Bitrate Experiment<\/a>. Джефф Этвуд провёл эксперимент и установил, что нет никакого смысла в мп3 более высокого битрейта, чем 160.<\/li>\n  <li><a href=\"http:\/\/www.codinghorror.com\/blog\/2012\/06\/the-php-singularity.html\">The PHP Singularity<\/a>. Он же в очередной раз про ПХП.<\/li>\n  <li><a href=\"http:\/\/www.businessinsider.com\/the-iphone-is-5-years-old-2012-6\">The iPhone Is 5 Years Old<\/a>. Статья странного чувака Генри Блоджета о том, как Айфон изменил мир за 5 лет. Ну и сюда же Джим Далримпл <a href=\"http:\/\/www.loopinsight.com\/2012\/06\/29\/iphone-turns-5-here-are-the-naysayers\/\">с лучшими цитатами<\/a> скептиков.<\/li>\n  <li><a href=\"http:\/\/clubs.ya.ru\/bem\/replies.xml?item_no=1398\">История создания БЭМ<\/a>. После того, как я опубликовал прошлую ссылку на статью про БЭМ, мне написал Виталий Харисов и сказал, что на самом деле начинать надо не оттуда, а отсюда вот. Чтобы въехать, откуда вообще растут ноги.<\/li>\n<\/ol>\n",
            "summary": "Например",
            "date_published": "2012-06-29T23:59:33+05:00",
            "date_modified": "2012-06-29T23:58:00+05:00",
            "tags": [
                "Айфон",
                "веб-разработка",
                "жизнь",
                "музыка",
                "ПХП",
                "цитаты",
                "чтиво"
            ],
            "_date_published_rfc2822": "Fri, 29 Jun 2012 23:59:33 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2997",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "2935",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/all\/weekend-reading-11\/",
            "title": "Что почитать на выходных — 11",
            "content_html": "<p>Понравилось недавно:<\/p>\n<ol start=\"1\">\n  <li><a href=\"http:\/\/www.lensrentals.com\/blog\/2012\/03\/hammerforum-com\">Hammerforum.com<\/a>. Если бы плотники на форумах общались как фотографы. «That’s because you have absolutely no skills. A good hammer user can drive nails with a 20 pound sledghammer with no problem.»<\/li>\n  <li><a href=\"http:\/\/startupsthisishowdesignworks.com\/\">Startups, this is how design works<\/a>. Видео-текстовое эссе о том, зачем стартапу дизайнер. Клёво и интересно сделано.<\/li>\n  <li><a href=\"http:\/\/www.nytimes.com\/interactive\/2012\/04\/08\/sunday-review\/a-passengers-lot-then-and-now.html?ref=sunday-review\">A Passenger’s Lot Then... And Now<\/a>. Сравнение условий на Титанике в 1912 году и на современном корабле. Я и не знал, что Титаник, оказывается, такой был крохотный по современным меркам.<\/li>\n  <li><a href=\"http:\/\/ilyabirman.net\/meanwhile\/2012\/04\/09\/2\/\">The Beauty of Silence<\/a>. Это я в английском блоге написал про тупость искусственного шума в электромобилях. Ничё, что я сам на себя ссылаюсь? Если вы меня там не читаете, самое время подписаться и, главное, рассказать всем своим англоговорящим друзьям.<\/li>\n  <li><a href=\"http:\/\/me.veekun.com\/blog\/2012\/04\/09\/php-a-fractal-of-bad-design\/\">PHP: a fractal of bad design<\/a>. Чувак-питонист рассказывает о том, о чём просто не могут молчать Питонисты: о том, как плох и ужасен ПХП. Всё это, конечно, <a href=\"http:\/\/www.codinghorror.com\/blog\/2008\/05\/php-sucks-but-it-doesnt-matter.html\">не имеет значения<\/a>, но работа, которую провёл автор по классификации всех корявостей ПХП, вызывает уважение. Я <a href=\"http:\/\/ilyabirman.net\/meanwhile\/2012\/04\/13\/1\/\">вот<\/a> тоже высказываюсь по теме.<\/li>\n  <li><a href=\"http:\/\/www.reigndesign.com\/blog\/love-hotels-and-unicode\/\">Love Hotels and Unicode<\/a>. О том, откуда в Уникоде взялись символы U+1f3e9 Love Hotel и U+1f4a9 Pile of Poo.<\/li>\n<\/ol>\n",
            "summary": "Понравилось недавно",
            "date_published": "2012-04-13T23:06:53+05:00",
            "date_modified": "2012-05-18T20:53:44+05:00",
            "tags": [
                "дизайн",
                "программирование",
                "ПХП",
                "смешное",
                "ссылки",
                "чтиво"
            ],
            "_date_published_rfc2822": "Fri, 13 Apr 2012 23:06:53 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2935",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "2894",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2012\/02\/11\/1\/",
            "title": "Что почитать в выходные — 4",
            "content_html": "<p>Понравилось на этой неделе:<\/p>\n<ol start=\"1\">\n  <li><a href=\"http:\/\/37signals.com\/svn\/posts\/3097-developing-for-old-browsers-is-almost-a-thing-of-the-past\">Developing for old browsers is (almost) a thing of the past<\/a>. 37сигналов рассказывают, как они отпиливают левые браузеры. Горячо поддерживаю.<\/li>\n  <li><a href=\"http:\/\/www.lettersofnote.com\/2012\/01\/to-my-old-master.html\">To My Old Master<\/a>. Письмо бывшего раба своему бывшему владельцу (США, 1865 год). Обалдеть.<\/li>\n  <li><a href=\"http:\/\/www.caranddriver.com\/features\/how-to-adjust-your-mirrors-to-avoid-blind-spots\">Adjust Your Mirrors to Avoid Blind Spots<\/a>. Совет по настройке боковых зеркал машины. Контринтуитивно, но по утверждению авторов статьи — более безопасно. Езжу так уже три дня, пока немного разрывает мозг.<\/li>\n  <li><a href=\"http:\/\/boingboing.net\/2011\/11\/14\/what-the-vaio-z-says-about-son.html\">What the Vaio Z says about Sony’s little design problem<\/a>. Про разницу в подходах к дизайну у Эпла и Сони.<\/li>\n  <li><a href=\"http:\/\/bolknote.ru\/2012\/02\/09\/~3567\/#12\">Как добавить ПХП в список шеллов в Автоматоре<\/a>. Женя Степанищев объясняет, как прикрутить ПХП-сервис иначе, чем я показывал — возможно, кому-то так больше понравится.<\/li>\n  <li><a href=\"http:\/\/parislemon.com\/post\/17328048747\/still-fucking-hate-email\">Still Fucking Hate Email<\/a>. Эм-Джи Сиглер предлагает изменить отношение к почте, смотреть на неё как на ленту твиттера, которая проносится мимо тебя, а не как на инбокс, который нужно непременно разобрать. Радикально.<\/li>\n<\/ol>\n",
            "summary": "Понравилось на этой неделе",
            "date_published": "2012-02-11T03:44:34+05:00",
            "date_modified": "2012-05-01T19:26:55+05:00",
            "tags": [
                "автомобиль",
                "браузеры",
                "дизайн",
                "дороги",
                "жизнь",
                "Мак",
                "программирование",
                "ПХП",
                "чтиво",
                "эл. почта"
            ],
            "_date_published_rfc2822": "Sat, 11 Feb 2012 03:44:34 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2894",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "2898",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2012\/02\/09\/1\/",
            "title": "Как написать сервис на ПХП",
            "content_html": "<p>На Маке есть такая странная фича — сервисы. Это такие то ли программы, то ли не программы, которые встраиваются во все приложения и могут как-то преобразовывать контент в них. Например, они могут делать что-то с выделенным текстом. Если прикрутить такой текстовый сервис, то он будет доступен по правой кнопке наряду со стандартными операциями типа копирования, трансформации или произнесения вслух.<\/p>\n<p>Разные приложения могут добавлять свои сервисы, например после установки Твиттера любой выделенный текст можно твитнуть. Но текст — это не обязательно. Сервис может уметь что-то делать с файлами или другими объектам. <a href=\"http:\/\/www.devontechnologies.com\/products\/freeware.html\">Девон-технолоджис<\/a> много всяких сервисов дают. Сервисами никто не пользуется, потому что фиг поймёшь, как с ними совладать и какую пользу они могут принести. Не пользовался особо и я.<\/p>\n<p>Но недавно назрела необходимость сделать себе макросы, которые бы заменяли простые куски текста на большие простыни ХТМЛ-кода. Чтобы писать pic image.jpg, а оно превратилось в целую кучу вёрстки для правильного размещения изображения, да ещё и размер файла само вписывало. Причём не в редакторе кода, где таких фич завались, а в любом месте. Долго объяснять, зачем, но надо было. Программерский мозг не терпит неавтоматизированной работы.<\/p>\n<p>Оказалось, что всё очень просто. Запускаем Автоматор (это ещё одна недооценённая фича Мака) — он спросит, что мы хотим создать. Выбираем сервис и делаем в нём одно-единственное действие — выполнить скрипт:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/phpservice.jpg\" width=\"632\" height=\"434\" alt=\"\" \/>\n<\/div>\n<p>Настраиваем, чтобы выделенный текст шёл скрипту в stdin и заменялся результатом выполнения (всё в правой части скриншота). Осталось написать сам скрипт на ПХП, а это может даже ребёнок (no pun intended). Саша Карпинский научил, что в начале скрипта нужно заклинание, чтобы он заработал, то есть всё вместе получится как-то так:<\/p>\n<pre class=\"e2-text-code\"><code>#!\/usr\/bin\/php\n&lt;?\n$input = trim (file_get_contents ('php:\/\/stdin'));\nif ($input == 'SOPA') die ('PIPA');\necho $input;\n?&gt;<\/code><\/pre><p>Ну, например. А дальше идём в «Систем преференсес», в настройку клавиатуры, и вешаем наш волшебный сервис на любую кнопку. Да, ПХП на Маке встроенный, то есть ничё про это думать не надо.<\/p>\n",
            "summary": "На Маке есть такая странная фича — сервисы. Это такие то ли программы, то ли не программы, которые встраиваются во все приложения и могут как-то преобразовывать контент в них",
            "date_published": "2012-02-08T23:05:12+05:00",
            "date_modified": "2013-12-29T23:29:14+05:00",
            "tags": [
                "Мак",
                "программирование",
                "ПХП"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/phpservice.jpg",
            "_date_published_rfc2822": "Wed, 08 Feb 2012 23:05:12 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2898",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": true,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/phpservice.jpg"
                ]
            }
        },
        {
            "id": "2425",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2009\/05\/12\/1\/",
            "title": "Нотация для названий функций",
            "content_html": "<p>В Какао мне очень нравится, как используется возможность «Объектного Си» вставлять параметры прямо в название методов («селекторов»):<br \/>\n<tt>[someObject doStuffWithThing:x andThing:y usingParameter:z];<\/tt><\/p>\n<p>Получаются нормальные предложения. В большинстве языков так делать нельзя, однако формулировать названия функций так, чтобы параметры продолжали предложение, никто не запрещает. Если параметр всего один, или параметры образуют очевидную последовательность, то это добавит удобочитаемости. Я принял нотацию, согласно которой название функции завершается подчёркиванием, если оно составлено по такому принципу. В этом случае открывающая скобка не отбивается пробелом (вообще, я всегда отбиваю; меня страшно бесит, что в ЦССе так делать нельзя).<\/p>\n<p>Пример перевода:<br \/>\n<tt>e2_note_by_id ($id)<\/tt> → <tt>e2_note_with_id_($id)<\/tt>.<\/p>\n<p>А так могли бы выглядеть некоторые функции с несколькими параметрами:<br \/>\n<tt>do_stuff_at_($x, $y)<\/tt>,<br \/>\n<tt>do_stuff_with_date_($year, $month, $day)<\/tt>.<\/p>\n<p>Если параметры не образуют очевидной последовательности или нормально переформулировать смысл функции не удаётся, то функция пишется «по старинке», без подчёркивания в конце:<br \/>\n<tt>e2_store_cache ($path, $data, $secure)<\/tt>.<\/p>\n<p>А какие вы используете хитрости для повышения удобочитаемости кода?<\/p>\n",
            "summary": "В Какао мне очень нравится, как используется возможность «Объектного Си» вставлять параметры прямо в название методов",
            "date_published": "2009-05-12T16:01:17+05:00",
            "date_modified": "2021-05-19T11:42:16+05:00",
            "tags": [
                "Какао",
                "программирование",
                "ПХП"
            ],
            "_date_published_rfc2822": "Tue, 12 May 2009 16:01:17 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2425",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "2236",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2008\/09\/19\/2\/",
            "title": "Боремся с 77 февраля: мой вариант",
            "content_html": "<p>В общем, вчерашняя моя задачка во многом потеряла смысл, когда Дима Смирнов указал мне на наличие функции checkdate (). Просто когда проблема возникла я не пошёл читать мануал в поисках готовой функции, так как был уверен, что после того, как я намучился с проблемой часовых поясов и летнего времени (и стал мировым экспертом в этой области), я уже по-любому знаю <i>все<\/i> функции, связанные с датой временем. Оказалось, что я ошибся.<\/p>\n<p>Впрочем, придумывать сложной математики мне не пришлось. Моё решение было однострочным и работало так:<\/p>\n<pre class=\"e2-text-code\"><code>return (\n  gmdate ('Y\/n\/d', gmmktime (0, 0, 0, $m, $d, $y))\n  == $y .'\/'. $m .'\/'. $d\n);<\/code><\/pre><p>Функция mktime умеет делать нормальный «тайм-штамп» из любых входных параметров. Например, если дать ей 25 часов 99 минут 32 декабря 2008 когда, то она вернёт штамп для 2 часов 39 минут 2 января 2009 не поперхнувшись.<\/p>\n<p>Это свойство функции mktime () страшно удобно, потому, что если нужно посчитать, какими будут дата и время через 55 часов, то можно тупо прибавить 55 к часам и забыть про суточные, месячные и годовые переходы, забыть про учёт високосности — функция всё сделает сама.<\/p>\n<p>Короче, критерий правильности даты — то, что функции не пришлось ничего «исправлять». (На самом деле, я уверен, что функция ничего и не исправляет, просто формулы в ней написаны так, чтобы всё работало независимо от корректности входных параметров.) А GMT-версии функций я использую «для надёжности», чтобы нигде часовые пояса не могли что-нибудь испортить.<\/p>\n<p>Сергей Коваленко в <a href=\"\/meanwhile\/2008\/09\/19\/1\/comments\/\">комментариях к прошлой заметке<\/a> предложил это же решение, причём совершенно справедливо не стал проверять день.<\/p>\n",
            "summary": "В общем, вчерашняя моя задачка во многом потеряла смысл, когда Дима Смирнов указал мне на наличие функции checkdate",
            "date_published": "2008-09-19T13:40:25+05:00",
            "date_modified": "2021-07-07T11:43:15+05:00",
            "tags": [
                "программирование",
                "ПХП"
            ],
            "_date_published_rfc2822": "Fri, 19 Sep 2008 13:40:25 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2236",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "2235",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2008\/09\/19\/1\/",
            "title": "Боремся с 77 февраля",
            "content_html": "<p>Если зайти по вот такому адресу — <a href=\"http:\/\/ilyabirman.ru\/meanwhile\/2008\/02\/77\/\">http:\/\/ilyabirman.ru\/meanwhile\/2008\/02\/77\/<\/a> — то вместо ожидаемой страницы 404 мы увидим страницу, говорящую о том, что 77 февраля заметок нет. Это, конечно, не беда, но если это можно решить по-простому, то хочется взять, да и решить, правда?<\/p>\n<p>Я это уже исправил в v1793, но на сайте пока крутится v1792  (последняя доступная всем остальным версия — v1746). Сначала я в функции, отвечающей за выдачу страницы архива, написал:<\/p>\n<pre class=\"e2-text-code\"><code>if (!e2_date_possible ($year, $month, $day)) return e2_error404_mode ();<\/code><\/pre><p>А потом написал функцию  e2_date_possible (), которая получилась не намного длиннее.<\/p>\n<p>Задача: придумайте функцию e2_date_possible () лучше моей (не видя мою).<\/p>\n<p><b>Update<\/b>:<\/p>\n<blockquote>\n<p>Дмитрий Смирнов: Ты изобрел функцию checkdate, поздравляю!<\/p>\n<\/blockquote>\n<p>Принимаю поздравления. Это, кстати, подтверждает <a href=\"http:\/\/bolknote.ru\/2008\/09\/18\/~1863\">правоту Болка<\/a>. Тем не менее, задачка остаётся, просто к ней добавляется (в реальной жизни ненужное) условие неиспользования функциии checkdate ().<\/p>\n",
            "summary": "Если зайти по вот такому адресу — http:\/\/ilyabirman.ru\/meanwhile\/2008\/02\/77\/ — то вместо ожидаемой страницы 404 мы увидим страницу, говорящую о том, что 77 февраля заметок нет",
            "date_published": "2008-09-19T03:18:43+05:00",
            "date_modified": "2021-07-07T11:44:29+05:00",
            "tags": [
                "программирование",
                "ПХП"
            ],
            "_date_published_rfc2822": "Fri, 19 Sep 2008 03:18:43 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2235",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": []
            }
        },
        {
            "id": "2093",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2008\/02\/11\/1\/",
            "title": "Как поднять Апач и ПХП на Айфоне",
            "content_html": "<p>Чтобы организовать Апач и ПХП на Айфоне нам понадобится:<\/p>\n<ul>\n  <li>вайфай (либо куча терпения и денег, если качать всё через GPRS);<\/li>\n  <li>телефон, на котором стоят терминал, Community Sources и BSD Subsystem (не уверен, что она нужна, но у меня стояла);<\/li>\n  <li>компьютер с установленным каким-нибудь софтом для хождения по файловой системе Айфона (у меня это iBrickr).<\/li>\n<\/ul>\n<p>Понятно, что поставить что-либо на Айфон благодаря Installer.app совсем не трудно, но в случае с Апачем и ПХП вопрос в том, как это в итоге заставить работать. Денвера для Айфона, как мы понимаем, нет. В общем, после того, как Апач (категория Network) и ПХП (категория Development) установлены обычным путём, нам нужно пойти в терминал и написать (осторожно, в терминале не работает бекспейс):<\/p>\n<pre class=\"e2-text-code\"><code>PATH=$PATH:\/opt\/iphone\/bin\/\nexport PATH<\/code><\/pre><p>Теперь идём в httpd.conf (\/etc\/httpd\/httpd.conf) и пишем про ПХП вот такие строчки (каждую в своё логичное место):<\/p>\n<pre class=\"e2-text-code\"><code>ScriptAlias \/php \/opt\/iphone\/bin\nAddType application\/x-httpd-php .php\nAction application\/x-httpd-php &quot;\/php\/php-cgi&quot;<\/code><\/pre><p>Теперь идём в терминал и перезапускаем Апач:<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/ilyabirman.ru\/meanwhile\/pictures\/iphone-term-apachectl-restart.jpg\" width=\"512\" height=\"683\" alt=\"apachectl restart\" \/>\n<\/div>\n<p>Осталось закачать скрипт с вызовом phpinfo () в \/Library\/WebServer\/Documents\/ и направить Сафари на localhost\/название-скрипта.<\/p>\n<p>То есть всё довольно-таки несложно. Другой вопрос — что со всем этим можно сделать интересного. Этот вопрос я пока изучаю, и у меня есть ощущение, что тут есть целый мир для экспериментов.<\/p>\n",
            "summary": "Чтобы организовать Апач и ПХП на Айфоне нам понадобится",
            "date_published": "2008-02-11T14:41:34+05:00",
            "date_modified": "2021-07-08T11:17:06+05:00",
            "tags": [
                "Айфон",
                "ПХП"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/iphone-term-apachectl-restart.jpg",
            "_date_published_rfc2822": "Mon, 11 Feb 2008 14:41:34 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "2093",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/iphone-term-apachectl-restart.jpg"
                ]
            }
        },
        {
            "id": "935",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2004\/11\/22\/3\/",
            "title": "Оптимайз — 3",
            "content_html": "<p>Пришла в голову очередная оптимизация; не понимаю пока, будет работать или нет.<\/p>\n<p>e2 сейчас уже довольно прилично тормозит — иногда генерит страницу по 0,15-0,2 сек. Причина тормозов пришла откуда не ждали: очень много времени уходит на то, чтобы просто пропарсить core.php, который уже почти 200 килобайт весит. Разбивать всё это на много файлов — будет ещё больше тормозов, т. к., как мы уже проходили, сильно тормозит include. Собственно, поэтому я и стал всё собирать в единый файл.<\/p>\n<p>Значит, нужно как-то сделать так, чтобы для генерации каждой страницы парсилось только то, что нужно. Но как это сделать?<\/p>\n<p>Идея такая. Ведь просто <i>тупое считывание<\/i> 200 КБ не может быть долгим, так? Тормозит, потому, что это <i>парсится<\/i> всё. А что, если мы эти 200 КБ разобъем на функциональные куски (ФК), каждый из них сделаем просто строкой, но оставим в <i>одном<\/i> файле, а при вызове функции из нужного ФК, будем вместо include’а эту строку eval ()’ить? Если это сработает, то можно пойти дальше: запихать разные ФК прямо в реестр, который мы всё равно считываем. Тогда ещё на один include меньше будет.<\/p>\n<p>Или ерунда? Аргументы приветствуются.<\/p>\n<p><b>Update<\/b>: Bolk говорит, eval () работает медленнее, чем include. Ну, а что ещё можно с этим сделать?<\/p>\n",
            "summary": "Пришла в голову очередная оптимизация; не понимаю пока, будет работать или нет",
            "date_published": "2004-11-22T16:34:50+05:00",
            "date_modified": "2004-11-22T16:52:49+05:00",
            "tags": [
                "программирование",
                "ПХП",
                "Эгея"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg",
            "_date_published_rfc2822": "Mon, 22 Nov 2004 16:34:50 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "935",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg"
                ]
            }
        },
        {
            "id": "919",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2004\/11\/16\/1\/",
            "title": "Windows-приложения на PHP",
            "content_html": "<p>Мне всегда хотелось писать Windows-приложения на PHP, ведь это такой замечательный язык.<\/p>\n<p>Когда-то я пробовал PHPGTK, но мне сразу не понравилось. Он генерил совершенно отвратительный интерфейс, не имеющий никакого отношения к Windows. Как я понимаю, там люди просто портировали под Windows какой-то первобытный оконный интерфейс из какого-то линукса. Казалось бы, взялись за дело — ну доведите его до ума: замените вызовы своего портированного кода вызовами нормального WinAPI. Ан-нет, это не наш путь.<\/p>\n<p>Но всё меняется, когда приходят они. Если за дело берутся Windows-разработчики, то на выходе получается намного более удобоваримый продукт, <a href=\"http:\/\/winbinder.sourceforge.net\/overview.php\">WinBinder<\/a>. WinBinder позволяет делать нормально-интерфейсовые приложения под Windows. Больше того, он позволяет даже собрать такое приложение в exe-файл! Нужно только разобраться, как это делать (смайлик).<\/p>\n<p>В общем, очень интересная штука.<\/p>\n",
            "summary": "Мне всегда хотелось писать Windows-приложения на PHP, ведь это такой замечательный язык",
            "date_published": "2004-11-16T02:17:07+05:00",
            "date_modified": "2004-11-16T02:17:07+05:00",
            "tags": [
                "Виндоус",
                "программирование",
                "ПХП"
            ],
            "_date_published_rfc2822": "Tue, 16 Nov 2004 02:17:07 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "919",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "891",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2004\/10\/23\/5\/",
            "title": "Избавиться от PHPSESSID",
            "content_html": "<p>Почему-то очень часто бывает, что если сайт открываешь в браузере первый раз в сессии, то все ссылки обрастают PHPSESSID’ами. F5 — и всё в порядке, PHPSESSID переползает из урла в куки. Мне нужно как-то сделать, чтобы PHPSESSID в урле не использовался, даже если возникли какие-то проблемы с куки.<\/p>\n<p>Не получается положить сессию в куки — значит забудь о сессии, главное чтобы урл был чистым.<\/p>\n<p>Как этого добиться?<\/p>\n",
            "summary": "Почему-то очень часто бывает, что если сайт открываешь в браузере первый раз в сессии, то все ссылки обрастают PHPSESSID’ами",
            "date_published": "2004-10-23T18:59:16+05:00",
            "date_modified": "2004-10-24T00:01:20+05:00",
            "tags": [
                "веб-разработка",
                "ПХП"
            ],
            "_date_published_rfc2822": "Sat, 23 Oct 2004 18:59:16 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "891",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "1300",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2004\/09\/03\/1\/",
            "title": "Режимы и службы",
            "content_html": "<p>Я, наконец, решил написать про свою идеологию «режимов и служб» (РиС) — почти универсальный принцип построения стройных yet гибких PHP-приложений. Наверное, этот подход подойдёт и в случае использования других серверных языков, но про них я ничего не знаю. Принцип «режимов и служб» реализован в Plif One и в e2.<\/p>\n<p>Всё началось с того, что мне никогда не нравилось, когда в веб-приложении есть несколько исполняемых php-скриптов (здесь я буду называть исполняемыми скрипты, которые содержат что-нибудь, кроме описаний функций). Типа, для главной страницы — index.php, для страницы about — about.php и так далее. Это очень неудобный (=плохой) способ, т. к. он предполагает, например, copy\/paste кода дизайна во все скрипты. Многие будут возражать, что код дизайна можно вынести в отдельные файлы и инклюдить их. Да, конечно, но сам include — это уже код, одинаковый во всех файлах. При таком раскладе нельзя даже переименовать включаемый файл, потому, что это потребует правки огромной кучи других. Потом, во всех файлах могут потребоваться какие-то «общедвижковые» API, находящиеся во всяких других инклюд-файлах. Эти инклюды тоже будут повторяться из файла в файл и их нельзя будет спокойно трогать. В общем, этот подход образует довольно каменный код.<\/p>\n<p>По абсолютно таинственным причинам, однако, именно он используется в подавляющем большинстве скриптов, которые я видел. Единственное исключение, которое приходит на ум — WackoWiki. Но сейчас речь не об этом. Речь о том, как сделать так, чтобы исполняемым был только один скрипт (index.php) и при это всё отлично работало. Условно все действия, выполняемые скриптом, можно поделить на 1) генерацию какого-то контента и скармливание его браузеру, и 2) обработку каких-нибудь POST-запосов.<\/p>\n<p>Первый постулат принципа РиС: не бывает скриптов, которые бы хотя бы в какой-то мере сочетали первое и второе.<\/p>\n<h2>Режим<\/h2>\n<p>Термин «режим» возник очень просто: я часто делал, чтобы страницы были видны по адресам вида index.php?mode=about (mod_rewrit’ом это легко доводится до красоты, сейчас не об этом), т. е. называл переменную словом mode. Поэтому, <i>проход по скрипту, в результате которого генерируется и скармливается браузеру какой-то контент, называется режимом<\/i>. Для работы с режимами пишется функция («менеджер режимов»):<\/p>\n<pre class=\"e2-text-code\"><code>01 function modes () {\n02   global $mode, $content;\n03   $mode = @$_GET['mode'];\n04   if (!$mode) $mode = 'frontpage';\n05   @require_once 'system\/'.$mode.'.php'; # например\n06   if (!function_exists ($mode.'_mode')) $mode = 'error404';\n07   $content = call_user_func ($mode.'_mode');\n08 }<\/code><\/pre><p>Что она делает — понятно. Ага? Каждый режим генерирует своя функция. Его внешний вид (HTML) она возвращает менеджеру режимов, а он это запихивает в глобальную переменную $content.<\/p>\n<h2>Служба<\/h2>\n<p><i>Проход по скрипту, в результате которого обрабатывается какая-нибудь информация из форм, например, а HTML’а браузеру не передаётся, называется службой<\/i>. Службы обрабатываются так (это «менеджер служб»):<\/p>\n<pre class=\"e2-text-code\"><code>01 function services () {\n02   global $service;\n03   $service = @$_GET['service'];\n04   if (!$service) return;\n05   @require_once 'system\/'.$service.'.php';\n06   if (!function_exists ($service.'_service')) die ('Служба не найдена');\n07   $go_to = call_user_func ($service.'_service');\n08   if (!$go_to) $go_to = @$_POST['came_from'];\n09   if (!$go_to) $go_to = 'http:\/\/'.$_SERVER['HTTP_HOST'];\n10   header ('Location: '.$go_to);\n11 }<\/code><\/pre><p>Имея эти функции, index.php мы можем оформить примерно так:<\/p>\n<pre class=\"e2-text-code\"><code>01 &lt;?\n02 require_once 'ms.php'; # modes and services\n03 services ();\n04 modes ();\n05 echo design ();\n06 ?&gt;<\/code><\/pre><p>Рассмотрим теперь всё это подробнее. Сначала мы вызываем менеджер служб, потому, что это логично (смайлик). Он смотрит, не нужно ли сейчас выполнить какую службу (строки 03-04). Если не нужно, то он возвращает управление функции main (). Если же нужно, то он выполняет службу (строка 07).<\/p>\n<p>Функция, реализующая службу, может вернуть URL, по которому она хочет перекинуть браузер после своего завершения (например. если функция обработала форму отправки комментария, то там может быть урл страницы со всеми комментариями). Если функция не вернула такой урл (строка 08), то тогда мы смотрим, не было ли в форме поля came_from, и если было, то считаем его значения искомым урлом. Если же и этого поля не оказалось (чего вообще-то не должно произойти, см. ниже), то мы перекидываем пользователя на главную (fallback).<\/p>\n<p>Допустим, мы добрались до modes (). Это происходит, когда в параметрах index.php не прописан вызов службы (например, index.php?service=post-comment). Тогда если режим не указан, мы считаем, что мы на главной. Если функция-режим не найдена, то мы выполняем режим 404-й ошибки. Функция-режим всегда возвращает строку — HTML, который нужно показать пользователю. Разумеется, она выдаёт только ту часть HTML, которая в разных режимах разная. В результате, всё это попадает в глобальную переменную $content, вокруг которой в функции design () мы рисуем что нашей душе угодно. Точка.<\/p>\n<p>Теперь про came_from. Ясно, что форма — это режим. Значит, её генерируют какие-то функции-режимы. Мы можем ввести понятие режим-форма и определить для него требование: любая форма должна содержать скрытый input с именем came_from и значением, равным $_SERVER[’HTTP_REFERER’]. Процесс добавления этого input’а можно легко автоматизировать. Тогда менеджер служб всегда будет знать, куда перекинуть браузер после выполнения службы.<\/p>\n<p>Что это всё даёт? А то, что добавление новых типов страниц, функций и чего угодно на сайт, сделанный по такой схеме, становится очень простым делом — нужно просто создать файл в \/system и написать в нём, что он должен делать. Всю организационно-дизайнерскую работу возмёт на себя уже готовый каркас.<\/p>\n<p>Дальше, чтобы всё было совсем хорошо, можно сделать .htaccess примерно такого вида:<\/p>\n<pre class=\"e2-text-code\"><code>RewriteEngine On\nRewriteRule ^services\\\/([^\/.]+)(\\\/?)$ index.php?service=$1\nRewriteRule ^([^\/.]+)(\\\/?)$ index.php?mode=$1<\/code><\/pre><p>Кроме того, что это сделает все урлы красивыми, ещё и action у формы будет иметь модный вид «services\/post-comment».<\/p>\n<p>Внимание! У этого подхода есть и некоторые недостатки. Если вы нашли один из них, не нужно думать, что вы большой герой, и громко про это кричать. Недостатки — это нормальное явление для <i>всего<\/i>. Вы можете просто спокойно их изложить, тогда этого не придётся делать мне. Спасибо.<\/p>\n<p><i>Update:<\/i> Ужас, сколько идиотов в комментариях; не читайте их.<\/p>\n",
            "summary": "Я, наконец, решил написать про свою идеологию «режимов и служб» (РиС) — почти универсальный принцип построения стройных yet гибких PHP-приложений",
            "date_published": "2004-09-03T02:45:00+05:00",
            "date_modified": "2020-11-10T02:02:53+05:00",
            "tags": [
                "веб-разработка",
                "программирование",
                "ПХП",
                "Эгея"
            ],
            "image": "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg",
            "_date_published_rfc2822": "Fri, 03 Sep 2004 02:45:00 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "1300",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "highlight\/highlight.js",
                    "highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/ilyabirman.ru\/meanwhile\/pictures\/aegea-og-image.jpg"
                ]
            }
        },
        {
            "id": "800",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2004\/08\/19\/2\/",
            "title": "name ()",
            "content_html": "<p>Нужна функция <tt>function name (string param)<\/tt>, которая возвращает имя фактической переменной, переданной ей. Или я совсем тупой, или без debug_backtrace () тут не обойтись...<\/p>\n<p><tt>echo name ($some_var);<\/tt><\/p>\n<p>Должно вывести «some_var».<\/p>\n",
            "summary": "Нужна функция function name (string param), которая возвращает имя фактической переменной, переданной ей",
            "date_published": "2004-08-19T17:28:54+05:00",
            "date_modified": "2022-01-25T14:01:00+05:00",
            "tags": [
                "ПХП"
            ],
            "_date_published_rfc2822": "Thu, 19 Aug 2004 17:28:54 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "800",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "789",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2004\/08\/09\/2\/",
            "title": "SQLite рулит",
            "content_html": "<p><a href=\"http:\/\/www.zend.com\/php5\/articles\/php5-sqlite.php\">Тут<\/a> пишут про SQLite — базе данных, встроенной в PHP 5. Похоже, SQLite — это круто. Больше всего возбуждает:<\/p>\n<ul>\n  <li>отсутствие типов<\/li>\n  <li>транзакции<\/li>\n  <li>возможность засунуть в базу функцию и потом использовать её в SELECT’е или чём угодно<\/li>\n  <li>то, что вся база хранится просто в файле, т. е. 1) от хостера не требуется <i>ничего<\/i>, чтобы предоставить пользователю базу; 2) от пользователя не требуется <i>ничего<\/i>, чтобы включить поддержку баз данных в PHP 5.<\/li>\n<\/ul>\n<p>Похоже, переход с mySQL на SQLite будет чем-то вроде перехода с C на PHP.<\/p>\n<p>Но <i>самое интересное<\/i>, что есть вероятность, что <a href=\"http:\/\/masterhost.ru\">Masterhost<\/a> реализует-таки в «Панели управления» выбор между PHP 4 и PHP 5!<\/p>\n",
            "summary": "Тут пишут про SQLite — базе данных, встроенной в PHP 5. Похоже, SQLite — это круто. Больше всего возбуждает...",
            "date_published": "2004-08-09T20:56:50+05:00",
            "date_modified": "2009-12-08T12:05:55+05:00",
            "tags": [
                "ПХП"
            ],
            "_date_published_rfc2822": "Mon, 09 Aug 2004 20:56:50 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "789",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        },
        {
            "id": "749",
            "url": "https:\/\/ilyabirman.ru\/meanwhile\/2004\/07\/10\/3\/",
            "title": "Даёшь настройки в XML!",
            "content_html": "<p><a href=\"http:\/\/live.julik.nl\/2003\/12\/03.00.08.12\">Вот человек знает<\/a> как правильно писать на PHP и, в частности, как правильно писать блог. Похоже, сам-то он начитался книжек «Выучи XML за 5 минут», если считает, что XML лучше сериализованных массивов и его нужно пихать всюду... Обратите внимание на ЧПУ.<\/p>\n",
            "summary": "Вот человек знает как правильно писать на PHP и, в частности, как правильно писать блог. Похоже, сам-то он начитался книжек «Выучи XML за 5 минут», если считает",
            "date_published": "2004-07-10T20:12:24+05:00",
            "date_modified": "1970-01-01T08:00:00+05:00",
            "tags": [
                "идиоты",
                "из Фридберга",
                "ПХП"
            ],
            "_date_published_rfc2822": "Sat, 10 Jul 2004 20:12:24 +0500",
            "_rss_guid_is_permalink": "false",
            "_rss_guid": "749",
            "_rss_enclosures": [],
            "_e2_data": {
                "is_favourite": false,
                "links_required": [],
                "og_images": []
            }
        }
    ],
    "_e2_version": 4269,
    "_e2_ua_string": "Aegea 12.0a (v4269e)"
}