Рубрика "Так лучше не делать"
Итак, первое, с чего бы хотелось начать, использование ссылок в аргументах методов. Это встречается практически во всех классах MODX, которые не являются объектами базы данных. А ещё при вызове событий, если в них передаются объекты. А также во многих компонентах MODX.
Это наследие PHP4. В PHP5 работу с объектами переосмыслили. Теперь они хранятся в хэш таблицах. А переменная объекта хранит всего лишь ссылку на объект в этой хэш таблице, а не сам объект. Поэтому начиная с PHP5 нет необходимости принудительно передавать ссылку. Но даже в MODX3, требующей PHP7.1, данный легаси остался нетронутым.
Обратите внимание на картинку. Плагин PHP Inspections (PhpStorm) так об этом и говорит.
П.С. Про ссылки можно более подробно прочитать у меня на сайте https://modzone.ru/blog/?tag=PHP
Итак, первое, с чего бы хотелось начать, использование ссылок в аргументах методов. Это встречается практически во всех классах MODX, которые не являются объектами базы данных. А ещё при вызове событий, если в них передаются объекты. А также во многих компонентах MODX.
Это наследие PHP4. В PHP5 работу с объектами переосмыслили. Теперь они хранятся в хэш таблицах. А переменная объекта хранит всего лишь ссылку на объект в этой хэш таблице, а не сам объект. Поэтому начиная с PHP5 нет необходимости принудительно передавать ссылку. Но даже в MODX3, требующей PHP7.1, данный легаси остался нетронутым.
Обратите внимание на картинку. Плагин PHP Inspections (PhpStorm) так об этом и говорит.
П.С. Про ссылки можно более подробно прочитать у меня на сайте https://modzone.ru/blog/?tag=PHP
Помню, в сообществе периодически возникала дискуссия на тему - почему компонент, который создаёт в базе данных свои таблицы, не чистит базу от этих таблиц при своём удалении?
За последние пару лет я не встречал подобных вопросов. А кто-нибудь знает, как правильно удалять таблицы при деинсталяции компонента?
За последние пару лет я не встречал подобных вопросов. А кто-нибудь знает, как правильно удалять таблицы при деинсталяции компонента?
Рубрика "Так лучше не делать"
Разберём следующий пример легаси кода. Практически в любом классе MODX вы найдёте открытые наружу (public) свойства. Это нарушает один из принципов ООП - инкапсуляцию. И рикошетом бьёт по остальным.
Напомню, что всего этих принципов 4:
1. Абстракция
2. Инкапсуляция
3. Наследование
4. Полиморфизм
Современные стандарты программирования допускают использование открытых свойств только в исключительных случаях. Например, при использовании объектов DTO. В большинстве случаев свойства должны быть закрыты. А управление ими лучше организовать при помощи открытых методов. Таким образом вы сможете создавать абстракции с помощью интерфейсов, использовать наследование и полиморфизм. Кроме того, если вдруг потребуется, вы всегда можете повысить уровень видимости в классе-наследнике. А вот обратная операция невозможна - Fatal Error. А изменение модификатора в исходном классе нарушает обратную совместимость.
Открытые свойства в некоторых случаях могут пригодится для тестирования. Но их главный недостаток - невозможность их контролировать. Обратите внимание на картинку выше. Вы можете напрямую указать любые классы менеджера запросов (Request), менеджера ответа (Response), контекста, парсера, вместо массива с конфигами указать строку. Ну и т.д. Кстати говоря, метод
Ну и последнее замечание. Пустому свойству нет необходимости присваивать значение
Разберём следующий пример легаси кода. Практически в любом классе MODX вы найдёте открытые наружу (public) свойства. Это нарушает один из принципов ООП - инкапсуляцию. И рикошетом бьёт по остальным.
Напомню, что всего этих принципов 4:
1. Абстракция
2. Инкапсуляция
3. Наследование
4. Полиморфизм
Современные стандарты программирования допускают использование открытых свойств только в исключительных случаях. Например, при использовании объектов DTO. В большинстве случаев свойства должны быть закрыты. А управление ими лучше организовать при помощи открытых методов. Таким образом вы сможете создавать абстракции с помощью интерфейсов, использовать наследование и полиморфизм. Кроме того, если вдруг потребуется, вы всегда можете повысить уровень видимости в классе-наследнике. А вот обратная операция невозможна - Fatal Error. А изменение модификатора в исходном классе нарушает обратную совместимость.
Открытые свойства в некоторых случаях могут пригодится для тестирования. Но их главный недостаток - невозможность их контролировать. Обратите внимание на картинку выше. Вы можете напрямую указать любые классы менеджера запросов (Request), менеджера ответа (Response), контекста, парсера, вместо массива с конфигами указать строку. Ну и т.д. Кстати говоря, метод
modX::getRequest() проверяет класс и создаёт нужный, но открытое свойство сводит на нет данную проверку.Ну и последнее замечание. Пустому свойству нет необходимости присваивать значение
null. Достаточно просто его объявить без значения -private $property;.Рубрика "Так лучше не делать"
Допустим, у вас стоит задача сформировать путь к файлу
Идёт проверка последнего символа в строке пути. Если это не слеш, то нужно добавить его к строке. Но есть решение гораздо короче и проще
Допустим, у вас стоит задача сформировать путь к файлу
$path . $file и надо проверить, есть ли в конце $path слеш. В MODX эту задачу решили такpublic function postfixSlash($path) {
$len = strlen($path);
if (substr($path, $len - 1, $len) != '/') {
$path .= '/';
}
return $path;
}
Идёт проверка последнего символа в строке пути. Если это не слеш, то нужно добавить его к строке. Но есть решение гораздо короче и проще
rtrim($path, '/') . '/';К пути всегда добавляется слеш, но если путь оканчивается слешем, то функция
rtrim его удалит. Коротко и ясно. И не нужно писать отдельный метод.В коде MODX можно найти много примеров, когда нужно получить первый символ строки. Например в парсере, в зависимости от первого символа в теге элемента, определяется соответствующая логика.
В PHP есть возможность обращаться к строке как к массиву
Так проще и нагляднее.
$token= substr($tagName, 0, 1);
В PHP есть возможность обращаться к строке как к массиву
$token= $tagName[0];
Так проще и нагляднее.
Рубрика "Так лучше не делать"
Ещё одно наследие из далёкого PHP4. Тогда не было модификаторов доступа (public, protected, private), и названия закрытых методов начинали с нижнего подчёркивания. А так как есть инерция мышления, то даже при переходе на PHP5 такой подход остался в силе. В MODX можно найти public методы, начинающиеся с нижнего подчёркивания. В современных стандартах разработки такой подход считается плохим примером кодирования.
Кстати, так делают и в ванильном javascript. Там нет модификаторов.
Ещё одно наследие из далёкого PHP4. Тогда не было модификаторов доступа (public, protected, private), и названия закрытых методов начинали с нижнего подчёркивания. А так как есть инерция мышления, то даже при переходе на PHP5 такой подход остался в силе. В MODX можно найти public методы, начинающиеся с нижнего подчёркивания. В современных стандартах разработки такой подход считается плохим примером кодирования.
Кстати, так делают и в ванильном javascript. Там нет модификаторов.
Рубрика "Так лучше не делать"
В исходниках MODX можно нередко встретить такой код. Но давайте разберёмся почему это яркий пример говнокодинга.
В данном случае функция
Часто попадаются такие конструкции
В исходниках MODX можно нередко встретить такой код. Но давайте разберёмся почему это яркий пример говнокодинга.
В данном случае функция
empty() возвращает или true или false. Т.е. мы уже получаем булево значение. В итоге парсер PHP видит это так -true ? true : false;Т.е. если true, то возвращаем true. Если false, то false. Явный перебор.
// или так
false ? true : false;
Часто попадаются такие конструкции
$var == 'value' ? true : false;И тут первая часть возвращает булево значение. Но бывают случаи использования тернарного оператора без явного булева значения. Например, в кэш менеджере есть такая конструкция -
$results['system_settings'] = $this->generateConfig($partOptions) ? true : false;В данном случае достаточно явно привести значение к булеву типу -
$results['system_settings'] = (bool)$this->generateConfig($partOptions);
Кто-нибудь может мне объяснить, чем сборщики скриптов на javascript принципиально лучше сборщиков на PHP? Лично я вижу только повальную моду на JS.
У них обязательная зависимость от NodeJS. Они не умеют собирать скрипты на лету. И как следствие не могут собирать их со страницы как может делать тот же MinifyX. Для меня это явные минусы. Так в чем их преимущество?
У них обязательная зависимость от NodeJS. Они не умеют собирать скрипты на лету. И как следствие не могут собирать их со страницы как может делать тот же MinifyX. Для меня это явные минусы. Так в чем их преимущество?
Рубрика "Так лучше не делать"
Практически все авторы компонентов для MODX складывают все свои классы в папку
Практически все авторы компонентов для MODX складывают все свои классы в папку
model, которая, исходя из названия, предназначена для классов моделей, т.е. объектов в базе данных. Классы сервисов и другие вспомогательные классы должны размещаться в отдельных папках - services, src и т.п.Рубрика "Так лучше не делать"
Начиная с седьмой версии PHP активно двигается в сторону строгой типизации. До этого разработчикам в помощь были только статические анализаторы. MODX в этом плане выступает антипримером. На картинке выше видно, что используется строковый ключ для обращения к массиву с числовыми ключами. PHP так позволяет делать используя неявное преобразование типов. И если пробежаться по коду, то можно найти и другие примеры. Часто вместо
Начиная с седьмой версии PHP активно двигается в сторону строгой типизации. До этого разработчикам в помощь были только статические анализаторы. MODX в этом плане выступает антипримером. На картинке выше видно, что используется строковый ключ для обращения к массиву с числовыми ключами. PHP так позволяет делать используя неявное преобразование типов. И если пробежаться по коду, то можно найти и другие примеры. Часто вместо
true и false указывают 1 и 0.curl_setopt($ch, CURLOPT_NOBODY, !empty($options['curlopt_nobody']) ? $options['curlopt_nobody'] : 0);Иногда неявное преобразование используется в проверках
if ($foo) {...} // А если $foo = 'false'?
В общем, старайтесь избегать неявного преобразования типов. Это вводит в заблуждение разработчиков и может приводить к ошибкам.Рубрика "Так лучше не делать"
В MODX в условиях проверки можно часто встретить такой код. Что же тут не так? А дело в том, что эта проверка избыточна. Если заглянуть в документацию, то мы узнаем, что функция
Т.е. она делает то же самое, что и
В ядре MODX таких проверок очень много -
Я был очень удивлен, что даже Томас Джакоби (Jako), являющийся одним из контрибьютеров MODX, не знал этого.
В MODX в условиях проверки можно часто встретить такой код. Что же тут не так? А дело в том, что эта проверка избыточна. Если заглянуть в документацию, то мы узнаем, что функция
isset проверяет существование переменной. А вот что написано про функцию empty"Проверяет, считается ли переменная пустой. Переменная считается пустой, если она не существует или её значение равно false."
Т.е. она делает то же самое, что и
isset, плюс проверяет на false.В ядре MODX таких проверок очень много -
isset($_REQUEST['ctx']) && !empty($_REQUEST['ctx'])
...
isset($source['baseUrlRelative']) && !empty($source['baseUrlRelative'])
...
isset($_SERVER['HTTPS']) && !empty($_SERVER['HTTPS'])
...
isset($_FILES) && !empty($_FILES)
...
if ($filters && isset($filters[1]) && !empty($filters[1]))
и т.д.
Я был очень удивлен, что даже Томас Джакоби (Jako), являющийся одним из контрибьютеров MODX, не знал этого.
Уверен, многие знают библиотеку pdoTools. В основном её использование ограничивается сниппетами, входящими в библиотеку, и шаблонизатором Fenom. Но продвинутые разработчики используют ещё и API. Самые основные - это методы
Но не все разработчики знают, что для сниппетов добавлена возможность управления кэшированием как в тегах шаблонизатора. Т.е. для вызова некэшированного сниппета нужно перед именем указать знак "!". Это главное отличие от
А вот
П.С. Вообще и у шаблонизатора Fenom из pdoTools присутствует непродуманность функционала кэширования. Об этом я писал на своём сайте про сравнение шаблонизаторов.
getChunk и runSnippet. Они не только расширяют функциональные возможности аналогичных методов MODX, включая байндинги (@INLINE, @FILE и т.д.), но и оптимизируют их.Но не все разработчики знают, что для сниппетов добавлена возможность управления кэшированием как в тегах шаблонизатора. Т.е. для вызова некэшированного сниппета нужно перед именем указать знак "!". Это главное отличие от
modX::runSnippet(), который никогда не кэширует результат. А некоторые забывают про это и в результате получают кэшированные данные.А вот
pdoTools::getChunk() безразличен к признаку кэширования. Он никогда не кэширует полученный результат.П.С. Вообще и у шаблонизатора Fenom из pdoTools присутствует непродуманность функционала кэширования. Об этом я писал на своём сайте про сравнение шаблонизаторов.
Небольшая статья о проблеме слияния массивов в цикле.
https://modzone.ru/blog/2021/06/08/merging-arrays-in-a-loop/
https://modzone.ru/blog/2021/06/08/merging-arrays-in-a-loop/
modzone.ru
Слияние массивов в цикле | Зона разработки
Анонс.
Я закончил оптимизацию большого новостного сайта (около 200 тыс. ресурсов) и в ближайшее время планирую поделиться опытом, как удалось снизить нагрузку на сервер почти в 3 раза, ускорить отдачу страниц на порядок, увеличить скорость по Google SpeedPage с 37 до 80 (остальные 20 - это проблемы фронта).
Чтобы добиться этого пришлось подкрутить настройки, оптимизировать кэш-менеджер, доработать pdoTools и написать пару сниппетов и плагин для управления кэшем. Coming Soon.
Я закончил оптимизацию большого новостного сайта (около 200 тыс. ресурсов) и в ближайшее время планирую поделиться опытом, как удалось снизить нагрузку на сервер почти в 3 раза, ускорить отдачу страниц на порядок, увеличить скорость по Google SpeedPage с 37 до 80 (остальные 20 - это проблемы фронта).
Чтобы добиться этого пришлось подкрутить настройки, оптимизировать кэш-менеджер, доработать pdoTools и написать пару сниппетов и плагин для управления кэшем. Coming Soon.
Первая статья из цикла статей про оптимизацию больших сайтов. В ней мы поговорим о системных настройках.
https://modzone.ru/blog/2021/06/16/big-sites-optimization-p1/
https://modzone.ru/blog/2021/06/16/big-sites-optimization-p1/
modzone.ru
Оптимизация больших сайтов. ч.1 | Зона разработки
Продолжение цикла статей про оптимизацию больших сайтов. На этот раз будем говорить про подходы к кэшированию ресурсов (с примерами).
https://modzone.ru/blog/2021/06/18/big-sites-optimization-p2/
https://modzone.ru/blog/2021/06/18/big-sites-optimization-p2/
modzone.ru
Оптимизация больших сайтов. ч.2 | Зона разработки
Сегодня поговорим о популярной библиотеке pdoTools. Она предоставляет полный набор необходимых для разработки сайта сниппетов. Но для больших сайтов придётся её оптимизировать.
https://modzone.ru/blog/2021/06/30/pdotools-optimization/
https://modzone.ru/blog/2021/06/30/pdotools-optimization/
modzone.ru
Оптимизация pdoTools | Зона разработки
Опытные разработчики знают, что pdoPage самый медленный сниппет из всего набора сниппетов библиотеки pdoTools. Некоторые даже от него отказываются. Но его достаточно просто оптимизировать. Как раз об этом рассказано в моей статье.
https://modzone.ru/blog/2021/07/28/pdopage-optimization/
https://modzone.ru/blog/2021/07/28/pdopage-optimization/
modzone.ru
Оптимизация pdoPage | Зона разработки
Рубрика "Так лучше не делать"
В былые времена я принимал код MODX за образец и старался перенимать используемые в нём подходы и приёмы. И вот такой код
казался проявлением гибкости.
Но стоило только выглянуть за пределы MODX, в мир современной разработки, как оказалось, что такой подход считается вери бэд. Потому как понятный, хорошо поддерживаемый и легко тестируемый код должен следовать шаблону "Низкая связанность" (Low Coupling), описанный в законе Деметры. Т.е. объект не должен иметь зависимость от третьих объектов. Сегодня это обязательное требование в разработке.
https://habr.com/ru/post/319652/
В былые времена я принимал код MODX за образец и старался перенимать используемые в нём подходы и приёмы. И вот такой код
$this->fileHandler->modx->getCacheManager();
казался проявлением гибкости.
Но стоило только выглянуть за пределы MODX, в мир современной разработки, как оказалось, что такой подход считается вери бэд. Потому как понятный, хорошо поддерживаемый и легко тестируемый код должен следовать шаблону "Низкая связанность" (Low Coupling), описанный в законе Деметры. Т.е. объект не должен иметь зависимость от третьих объектов. Сегодня это обязательное требование в разработке.
https://habr.com/ru/post/319652/
Хабр
Закон Деметры
Введение На данный момент существует множество доказанных временем практик, помогающих разработчикам писать хорошо поддерживаемый, гибкий и удобно читаемый код.