Ещё библиотечки

И ещё вдогонку библиотечек на PHP.

axy/fs-paths: пути в ФС

Работа с путями к файлам. Разбор, нормализация, вычисление относительных и всё такое прочее.
Разные типы: Unix, Windows, UNC, даже URL’ы.
Любителям статики — статика, любителям объектов — объекты :)

Допустим, мы спарсили страничку по адресу http://example.com/news/view/?id=10, а в ней ссылки.
Как узнать, куда они ведут?

use axy\fs\paths\Paths;
 
$base = 'http://example.com/news/view/?id=10';
 
$links = [
    './../archive/?page=5#10',
    '/profile/',
    'http://site.loc/',
];
 
$urls = Paths::getAdapter(Paths::TYPE_URL);
 
foreach ($links as $link) {
    echo $link.' --> '.$urls->resolve($base, $link).PHP_EOL;
}

Результат:

./../archive/?page=5#10 --> http://example.com/news/archive/?page=5#10
/profile/ --> http://example.com/profile/
http://site.loc/ --> http://site.loc/

axy/callbacks: колбэки

В дополнение к стандартному callable связывание аргументов:

$callback = new Callback(['obj', 'sum'], [1, 2]);
$callback(3, 4); // $obj->sum(1, 2, 3, 4);

Или так:

$callback = ['obj', 'sum', [1, 2]];
// ...
Callback::call($callback); // $obj->sum(1, 2);

И связывание контекста заодно:

class MyClass
{
    public function getEventHandler()
    {
        return new Callback([$this, 'onEvent'], ['click'], true);
    }
 
    private function onEvent($event)
    {
        echo 'Event '.$event.'!';
    }
}
 
$obj = new MyClass();
$handler = $obj->getEventHandler();
 
// click
$handler(); // "Event click!". Private method was called

axy/magic: магия

Работа с магическими свойствами: отложенное создание магических свойств, надстройки над массивами, read-only и всё такое прочее.
Всё в виде трейтов, комбинируется, как угодно.

axy/envnorm: нормализация окружения

При запуске приложения, обычно, нужно поколдовать с глобальными настройками и окружением:

— Перехватить все ошибки и предупреждения и выдавать вместо них нормальное исключение.
— Перехватить исключения на верхнем уровне.
— Выводить ошибки при разработке и отключить на продакшене.
— Настроить недонастроенное окружение: правильную кодировку, таймзону путь к сендмайлу и т.п.

Просто пишем нужный конфиг и выполняем вначале:

use axy\envnorm\Normalizer;
 
$config = [
    'errors' => [
        'exceptionHandler' => 'myExceptionHandler',
    ],
    'datetime' => [
        'timezone' => 'Europe/Moscow',
    ],
];
 
Normalizer::createInstance($config)->normalize();

Всё в composer’е, на гитхабе и с документацией на подобии инглиша.

Source map и PHP

Написал библиотечку для работы с source map из нашего любимого похапе.

Если кто не знает что такое source map

Вот, допустим, у нас есть сайт, а у него много JavaScript-файликов. Ну и при деплое, мы их все, как порядочные люди, сливаем вместе и сжимаем каким-нибудь минификатором. И наши пользователи не грузят теперь себе много мелких файликов со всеми комментариями и отступами, а загружают парочку сжатых.

Единственная проблема, что в сжатом файле теперь у нас какая-то херь, которую совершенно невозможно дебажить. И сообщения об ошибках ведут теперь совершенно непонятно куда.

Однако, все современные минификаторы могут при сжатии ещё создавать файл source map.
В нём хитрым образом закодировано соответствие позиций в сгенерированном файле и в исходных.
В конце сжатого файла можно дописать ссылку на карту:

//# sourceMappingURL=script.min.js.map

И происходит волшебство. Грузится сжатый файл, а в отладчике браузера показываются исходные. Более того, так как в map-файле содержится только соответствие строк и столбцов между файлами, то можно спокойно дебажить TypeScript или какой-нибудь там Coffee прямо в браузере:

Ну, то есть вообще, что угодно:

Остальной текст под катом

PHP: обрезаем backtrace у exception

Разберём следующий кейс.

Разрабатываем мы на своём любимом похапэ некую систему и используем при этом некую библиотеку.
Пускай, например, это будет вот эта поделка для работы с базой данных.

И вот мы вызываем какой-то метод в нашей системе, тот вызывает ещё какой-то и так далее.
И, в конце концов, где-то мы обращаемся к вышеозначенной библиотеке:

$db->query('SELECT * FROM `test` WHERE `id`=?i')->el();

Запрос составили, в каком формате результат вернуть указали, куда данные вставлять с помощью плейсхолдера указали, а вот сами данные для этого плейсхолдера не предоставили.
Запамятовали в пылу разработки.

И вот, вызванный нами, метод query() начинает обращаться к каким-то другим классам библиотеки, те к следующим и так далее, всё как обычно.
В какой-то момент доходит дело до того, чтобы данные в запрос на нужные места вставлять и тут выясняется, что данных нет никаких. Ну и, ясное дело, всё валится с исключением:

go\DB\Exceptions\DataNotEnough: Data elements (0) less than the placeholders in /test/my/db/Helpers/Templater.php on line 126
 
Call Stack:
    1. {main}() /test/my/index.php:0
    2. callMyClass() /test/my/index.php:14
    3. MyClass->method() /test/my/index.php:11
    4. MyClass->selectDB() /test/my/MyClass.php:7
    5. go\DB\DB->query() /test/my/MyClass.php:20
    6. go\DB\DB->makeQuery() /test/my/db/DB.php:92
    7. go\DB\Helpers\Templater->parse() /test/my/db/DB.php:312
    8. preg_replace_callback() /test/my/db/Helpers/Templater.php:57
    9. go\DB\Helpers\Templater->placeholderClb() /test/my/db/Helpers/Templater.php:57

Смотрим мы печальными глазами на этот вывод и читаем сообщение, ага, забыли данных накидать.
А вот где именно это случилось, хрен поймёшь.
Исключение указывает на точку, где его выбросили, то есть глубоко в недрах библиотеки и делать нам там нечего.
Нам нужна та точка, где мы в эту библиотеку с невалидными данными вошли.

Остальной текст под катом

Константы, строки и ключи

Давайте тестанём не предмет скорости ещё какую-нибудь чепуху.

Вот, допустим, константы. Одно из применений констант, это обозначение «магических» чисел. Например:

class Compressor
{
    const GZIP = 1;
    const BZIP = 2;
    const RAR = 3;
    const HUERAR = 4;
 
    public function compress($str, $type)
    {
        // ...
    }
}

То есть у нас есть некое множество значений (типов сжатия) и для обозначения каждого мы придумываем от балды какое-то число. А, чтобы с числами не запутаться, придумываем поверх него константу. И используем:

$compressed = $compressor->compress($plain, Compressor::GZIP);

С незапамятных пор так ведётся. Ещё Страуструп молодым был.

Однако, иногда посещает мысль, что PHP, это не Си и со строками он работает намного веселее. И почему бы не написать крамольное:

$compressed = $compressor->compress($plain, 'gzip');

Остальной текст под катом

go\Request: доступ к данным запроса (PHP)

В рамках цикла «изобретение велосипедов» представляю релиз-кандидат библиотечки go\Request.

Библиотека осуществляет доступ к параметрам с которыми вызван наш сценарий: GET/POST-данные, куки, переменные окружения, заголовки запроса, настройки сервера и клиента, аргументы и опции командной строки и тому подобное.
Остальной текст под катом

Подключаем классы разным макаром (PHP)

Что-то давненько мы здесь не занимались глупостями.

Сегодня мы будем проводить тесты со всеми возможными нарушениями их чистоты и нагло манипулировать статистикой.

Вопрос: как правильно подключать в своём проекте классы, чтобы при этом сэкономить время на их подключение.

Варианты:

  • Старый добрый autoload(), как у всех нормальных людей.
  • Взять и собрать все классы в один файл, как многие учат.
  • Подключать нужные классы явно через require_once().
  • И новомодная штучка: Phar-архив.
  • Phar-архив ещё можно делать не простой, а со сжатием (GZ или BZ2).
  • Ну и phar’ом также два варианта: autoload() или прямое подключение вложенных файлов.
  • И поверх этого можно акселератором каким-нибудь пошаманить.

Остальной текст под катом

5.5

PHP 5.5 тут на днях вышел.

Генераторов понапихали, нескалярных ключей и всего такого прочего. Вобщем всё как у людей, кажется, скоро будет.

Но нет, никак до конца нормально сделать не могут. Хопа — расширение для хэширования паролей.

5 лет как уже пространства имён. Классы как уже 15. Генераторы теперь. Но всё равно нужно забить глобальное пространство хламом из функций и констант с префиксами. PASSWORD_BCRYPT, оспадепомилуй.

Git, mysql, бэкапы и очумелые ручки

Что-то давно мы тут не изобретали бессмысленных велосипедов.

Итак, ситуация: есть сервачок, на нём крутятся десяток сайтиков средней отстойности. Их базы данных весят в районе нескольких мегабайт и не слишком быстро наполняются.

Хотя сайтики и так себе, но потерять данные и разбираться с их заказчиками всё равно не хотелось бы. Поэтому нужно делать резервные копии.

Ничего из файловой системы сохранять не надо, базы небольшие, ставить и настраивать навороченные системы бэкапов лениво, а руки чешутся сделать что-нибудь бессмысленное и беспощадное. Ну так возьмём и сделаем это.
Остальной текст под катом

WordPress: похожие посты (хардкор-вариант)

Задача: в wordpress’е после статьи выводить список «похожие статьи».

Если у двух статей совпадает один из тегов или категория, то это похожие статьи. Чем больше тегов совпадает, тем сильнее похожие. Вывести нужно пяток наиболее похожих. Если у двух статей одна «релевантность», то выше выводить более свежую.

По запросу «wordpress similar posts» можно найти множество плагинов данной тематики. У них у всех отличный код, подробная документация и богатый набор настроек. Единственный минус: вместо похожих постов они выводят какую-то рандомную хероту.
Остальной текст под катом

Traits и т.п.

Две недели не писал, а пиздюлей мне никто так и не дал. Ну ладно, вот, допустим, трейты. Вещь вполне себе, как оказывается, терпимая.

Вообще, все нововведения в PHP неизменно радуют. Нужно только отвлечься от того, что все они сделаны через жопу.

Теоретики плачут, что Traits, это никакое тебе не множественное наследование в высоком понимании этого термина. А самый, что ни на есть, банальный автоматизированный копипаст.

Однако, если посмотреть на языки с нормальным множественным наследованием, оно всё равно там в большинстве случаев используется именно для копипаста. Да и вообще, чуть ли не вся история развития программирования, это история автоматизации копипаста.

Остальной текст под катом

По страницам:1234