Всем привет!
Пролог
С месяц назад я попробовал работать с AI и мне это дело понравилось. Пока я как ошпаренный пилил новые фичи для заказчика, применить AI к собственным проектам времени не было, но ни что не вечно под Луной. Когда то кончается и работа (к сожалению). У меня появилась возможность заняться собой, своими проектами и я ими занялся, поработал над ускорением двух, в этой статье расскажу про первый.
Исходно библиотека была условным междусобойчиком, нужным ни кому кроме меня. Но после пары статей тут на Хабре, и после того как толпы ринулись вкатываться в АйТи, какие то скачивания появились, за последний год плюс 10 000. Это не то чтобы накладывает ответственности, но даёт вдохновение развивать "проект".
Пару лет назад вышел пакет wplake/typed, я конечно сравнил производительность со своим sbwerewolf/language-specific, разница была в 10 раз, oops! Я открыл исходники, посмотрел, ни чего не понял и забил. Мой код был красивы, чужой код был быстрым, о вкусах не спорят.
Сейчас появилась возможность закинуть работу в AI, с подобной нудятиной он справляется на ура, я бы такое ни когда не осилил. С меня ТЗ, с него код, мы отличная пара :)
Что получилось
От базовой версии получилось ускориться в 4 раза, отставание от wplake/typed сократилось до "всего лишь" x2, то есть если вам критична скорость вам к wplake/typed, если вам критична читаемость выбирайте sbwerewolf/language-specific.
Разница между скоростью wplake/typed и красотой sbwerewolf/language-specific
Разница в подходах наглядно в коде ниже.
wplake/typed
use WPLake\Typed\Typed; $response = file_get_contents( 'https://geocode-maps.yandex.ru/1.x/?apikey=d3893dc1-c136-4084-b9c-4db26b00463e&geocode=Mohammed+Bin+Rashid+Boulevard+1&lang=en_US&format=json' ); $object = json_decode(json: $response, associative: true, flags: JSON_THROW_ON_ERROR); $path = 'response.GeoObjectCollection.featureMember.0.GeoObject.metaDataProperty.GeocoderMetaData.Address.formatted'; // значение с fallback $val = Typed::string($object, $path, 'Адрес не найден'); var_dump($val); /* string(77) "1, Mohammed Bin Rashid Boulevard, Downtown Dubai, Dubai, United Arab Emirates" */ $isReal = Typed::stringOrNull($object, $path) !== null; var_dump($isReal); /* bool(true) */
Я когда смотрю на эту "колбасу" ($path) у меня кровь из глаз, вам норм ?
sbwerewolf/language-specific
use SbWereWolf\LanguageSpecific\AdvancedArrayFactory; $response = file_get_contents('https://geocode-maps.yandex.ru/1.x/?apikey=d3893dc1-c136-4084-b9c-4db26b00463e&geocode=Mohammed+Bin+Rashid+Boulevard+1&lang=en_US&format=json'); $object = json_decode(json: $response, associative: true, flags: JSON_THROW_ON_ERROR); $data = new AdvancedArrayFactory()->makeAdvancedArray($object); $formatted = $data ->pull("response") ->pull("GeoObjectCollection") ->pull("featureMember") ->pull() ->pull("GeoObject") ->pull("metaDataProperty") ->pull("GeocoderMetaData") ->pull("Address") ->get("formatted") ->default("Адрес не найден"); $val = $formatted->str(); var_dump( $val); /* string(77) "1, Mohammed Bin Rashid Boulevard, Downtown Dubai, Dubai, United Arab Emirates" */ $isReal = $formatted->isReal(); var_dump( $isReal); /* bool(true) */
Вариант с записью в колонку тоже не айс, но если решишь переставить местами два элемента, то сделать это как то попроще. Можно конечно длинную строку записать через конкатенацию, но кто же так делает ?
Результаты измерений
Последняя версия моего пакета на момент начала "ускорения и перестройки" - 8.4.1, текущая версия - 10.4.5, текущая версия wplake/typed - 1.2.2. У ребят из wplake (кажется это разработка компании из РФ) всего 1000 скачиваний, не густо, надеюсь эта статья поднимет популярность их пакета.
Use case | 8.4.1 (было) | 10.4.5 (стало) | 1.2.2 (идеал) |
парсинг JSON happy path | 29.210 | 6.467 | 3.013 |
парсинг JSON missing path | 18.716 | 5.987 | 1.766 |
is element exists ? | 27.237 | 6.277 | 2.863 |
get type of value | 28.581 | 6.740 | 2.966 |
get value as is | 30.395 | 6.558 | 3.015 |
Получить все элементы-значения | 5.897 | 1.878 | не умеет |
Получить все элементы-массивы | 7.136 | 2.431 | не умеет |
AI делал замеры на основе примеров из предыдущей статьи (https://habr.com/ru/articles/874688/ читайте начиная с "Как пользоваться"). Там приведён пример из жизни когда мне этот пакет пригодился, если у вас схожие задачи, то может быть вам имеет смысл использовать sbwerewolf/language-specific.
Обратная совместимость
По ходу ускорения я выкинул ООПэшную лабуду про разделение ответственностей в виде двух классов, поэтому повысил мажорную версию, формально я нарушил обратную совместимость.
Второй раз пришлось повысить мажорную версию когда я решил сделать класс CommonValue иммутабельным. Формально это нарушает обратную совместимость, но сомневаюсь что в коде кто то устанавливал для индекса значение по умолчанию и потом два раза читал значение по этому индексу.
В целом все изменения косметические, в коде ни чего менять не надо. Сильные изменения под капотом, но для вас это бесплатно.
И была некоторая случайность при получении хотя бы какого элемента из массива, теперь это всегда первый элемент, результат работы кода стал более идемпотентным. Ещё появилась пара методов, но это тоже всё баловство.
Эпилог
Библиотеке уже скоро 5 лет, и я до сих пор не знаю для чего были сделаны эти тысячи скачиваний, если вам приходилось скачивать и пользоваться sbwerewolf/language-specific, то напишите об этом в комментариях, поделитесь впечатлениями.
