Как не хакать сторонние классы
Бывает, что вы используете какой-то сниппет или компонент, и он немного вас не устраивает. Вам нужно поправить буквально пару строк, но вы понимаете, что при обновлении эти измения пропадут.
Что же делать?
Все просто — нужно расширить сторонний класс своими методами. По сути, это очень похоже на «классные процессоры», только без процессоров и использовать можно везде — это стандартная возможность ООП.
Смысл в том, что нам нужно создать свой собственный класс, который будет наследовать исходный класс и заменять его методы.
Для примера заменим некоторые методы miniShop. Создаем файл /core/components/minishop/model/minishopext.class.php:
Значит, нам нужен теперь сниппет, для запуска нового класса. Можно просто переименовать сниппет miniShop в miniShopExt, или скопировать.
Теперь меняем в новом сниппете инициализацию класса с miniShop на miniShopExt:
miniShopExt унаследовал все методы от miniShop, кроме тех, которые прописаны в нем самом. Теперь нужно только заменить вызов сниппета [[!miniShop]] в корзине на [[!miniShopExt]].
Вот таким способом мы можем изменять любой сторонний класс как нам нужно. Самое главное — мы не лезем в чужой код и не теряем будущие обновления.
Это вообще очень хорошая практика: не хакать чужой код, а наследовать и расширять. В любой момент вы можете инициализировать оригинальный класс, или свой, расширенный.
Что же делать?
Все просто — нужно расширить сторонний класс своими методами. По сути, это очень похоже на «классные процессоры», только без процессоров и использовать можно везде — это стандартная возможность ООП.
Принцип
Смысл в том, что нам нужно создать свой собственный класс, который будет наследовать исходный класс и заменять его методы.
Для примера заменим некоторые методы miniShop. Создаем файл /core/components/minishop/model/minishopext.class.php:
<?php
//загружаем код класса miniShop
require_once 'minishop.class.php';
// extends - это и есть расширение/наследование
class miniShopExt extends miniShop {
// Тут мы инициализируем родительский класс
function __construct(modX &$modx,array $config = array()) {
return parent::__construct($modx, $config);
}
// Если назвать метод, как в родительском класе - это будет замена
// Если нет - добавление нового метода
function addToCart($id, $num = 1, $data = array()) {
// Копируем сюда исходный метод и меняем в нем, что нам нужно
}
function remFromCart($key) {
// И тут. Можно хоть весь класс переписать заново.
}
function newMethod() {
// А это новый метод, пишем тут свой код
}Мы подключили родительский класс, но не инициализировали. Запускать его мы будем через свой новый класс — miniShopExt.Значит, нам нужен теперь сниппет, для запуска нового класса. Можно просто переименовать сниппет miniShop в miniShopExt, или скопировать.
Теперь меняем в новом сниппете инициализацию класса с miniShop на miniShopExt:
if (!isset($modx->miniShop) || !is_object($modx->miniShop)) {
$modx->miniShop = $modx->getService('minishopext','miniShopExt', $modx->getOption('core_path').'components/minishop/model/minishop/', $scriptProperties);
if (!($modx->miniShop instanceof miniShopExt)) return '';
}Видите, мы запускаем класс miniShopExt из файла minishopext(.class.php) и сохраняем его в переменную $modx->miniShop, чтобы не переписывать весь сниппет.miniShopExt унаследовал все методы от miniShop, кроме тех, которые прописаны в нем самом. Теперь нужно только заменить вызов сниппета [[!miniShop]] в корзине на [[!miniShopExt]].
Заключение
Вот таким способом мы можем изменять любой сторонний класс как нам нужно. Самое главное — мы не лезем в чужой код и не теряем будущие обновления.
Это вообще очень хорошая практика: не хакать чужой код, а наследовать и расширять. В любой момент вы можете инициализировать оригинальный класс, или свой, расширенный.
Комментарии: 28
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
Мегареспект
$this->config['tplPaymentRow'] и аналогичные
Сделал вот так в расширении класса miniShopExt. Работает. Если это не правильно поправьте
function __construct(modX &$modx, array $config = array()) {
$snippet = $modx->getObject('modSnippet',array('name'=>'miniShop'));
$config = array_merge($snippet->getProperties(),$config);
parent::__construct($modx, $config);
}
А ваш метод ничем не хуже, главное, чтобы сниппет miniShop никуда не делся, иначе будет fatal error.
Ну и минимум на пару операций с БД выходит больше (достать сниппет, а потом его параметры).
Я подключаю в переименованном сниппете расширенный класс.
Тот в свою очередь запускает оригинальный класс.
При обновлении перезаписываются оригинальный сниппет и оригинальный класс, а расширенные — нет.
Оригинальный сниппет больше вообще не используется, только расширенный — после каждого обновления его можно просто удалять.
Хочется делать сразу более менее оптимально
Только это уже какая-то экономия на спичках =)
Или я гоню?
Поэтому, надо запускать функцию до и после создания объекта, потом отнимать одно значение от другого — получите примерный вес объекта.
php.net/manual/en/function.memory-get-usage.php
Еще раз спасибо
// Получаем сниппет miniShop, если не можем — ошибка
if (!$snippet = $modx->getObject('modSnippet',array('name'=>'cart'))) {return 'Error: can`t found miniShop snippet';}
// Нам нужны параметры сниппета
$scriptProperties = $snippet->getProperties();
Кушает 650 кб
Сделал свой класс
1. Создал core/components/minishop2/model/minishop2/minishop_my.class.php и там прописал класс
2. Скопировал сниппеты msOrder и msCart в msCart_my и msOrder_my соответсвенно
В новых сниппетах заменил
на
И заменил в корзине вызовы сниппетов msCart и msOrder на свои msCart_my и msOrder_my
Но Корзина выдает «Ошибка сервера 500»
Менять сам minishop2.class.php вовсе не нужно.
Ну и стандартный метод вызывает кое-какие события перед и после изменения статуса заказа.