Декодирование прокси-класса в OpenCart

Декодирование прокси-класса в OpenCart

От автора: чаще всего мы принимаем что-то как должное. Если это что-то работает, как нужно, мы не будем беспокоиться о его внутренней работе и пытаться понять лежащий в основе механизм. Говоря другими словами, мы не придаём значения, пока не начинаются проблемы! Мне всегда было интересно узнать о нескольких концепциях OpenCart, которые использовались во фреймворке, и одним из них был прокси класс. Именно про прокси классы OpenCart мы сегодня и поговорим.

Что такое прокси-класс?

Вы найдете различные материалы в Интернете, которые определяют термин прокси, но лучше всего даёт определение этому термину Википедия: Прокси-сервер в его самой общей форме — это класс, функционирующий как интерфейс к чему-то другому.

Таким образом, прокси делегирует элемент управления объекту, который он намеревается использовать, и действует от имени фактического класса, который был создан. Фактически, шаблон прокси-дизайна является очень популярным шаблоном, который по мере необходимости используется фреймворками. Учитывая, что обсуждение прокси-метода само по себе является такой широкой темой и выходит за рамки этой статьи, я быстро объясню, почему он так часто используется:

Действуйте как обертка, чтобы обеспечить дополнительную функциональность.

Задерживает создание дорогостоящих объектов так называемой ленивой загрузкой.

В контексте OpenCart можно сказать, что шаблон прокси используется для добавления функциональности в базовый прокси-класс. Сам по себе базовый прокси-класс не предоставляет ничего, кроме нескольких магических методов! В следующем разделе мы увидим, как прокси-класс обогащается во время выполнения за счёт добавления к нему какого-либо свойства.

Прежде чем перейти к следующему разделу, давайте мельком взглянем на прокси-класс. Он находится в system/engine/proxy.php.

Как мы видим, он реализует методы: __get(), __set(), и __call(). Среди них реализация метода __call() наиболее важна, и довольно скоро мы вернемся к ней.

Как работает прокси-класс с моделью

В этом разделе я объясню, как именно вызов $this->model_catalog_category->getCategory($category_id) работает из коробки. Фактически, история начинается со следующего утверждения.

Во время начальной загрузки фреймворк OpenCart хранит все общие объекты в объекте Registry, чтобы по желанию их можно было получить. В результате этого $this->load вызов возвращает Loader объект из реестра.

Класс Loader предоставляет различные методы для загрузки различных компонентов, но то, что нас здесь интересует — это модель метода. Давайте извлечём фрагмент model метода system/engine/loader.php.

Учитывая вышеприведенный пример, значение $route аргумента catalog/category, значение переменной $route дезинфицируется, и после этого вызывает событие before, позволяющее другим слушателям модуля изменять значение переменной $route.

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

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

После этого он создает объект Proxy.

Теперь обратите внимание на следующий for цикл — он гораздо больше, чем кажется.

В нашем случае значение $class должно быть ModelCatalogCategory. Фрагмент get_class_methods($class) загружает через него все методы ModelCatalogCategory класса и циклов. Давайте внимательно посмотрим , что он делает в цикле.

В цикле он вызывает callback метод того же класса. Интересно то, что метод обратного вызова возвращает вызываемую функцию, назначенную объекту $proxy, с ключом в качестве имени метода.

Конечно, прокси-объект не обладает такими свойствами; он будет создан на лету, используя магический метод _set()!

Затем объект $proxy добавляется в реестр, чтобы позже его можно было получить, когда это необходимо. Посмотрите на ключевой компонент метода set. В нашем случае это должен быть model_catalog_category.

В конце он вызовет событие after, чтобы другие слушатели модуля могли изменить значение переменной $route. Это одна часть истории. Давайте рассмотрим, что происходит, когда вы используете в своем контроллере следующее.

Этот $this->model_catalog_category фрагмент пытается найти соответствие для ключа model_catalog_category в реестре. Если вам интересно, как это сделать, просто взгляните на Controller определение класса в system/engine/controller.php файле — он предоставляет магический метод __get(), который это делает.

Как мы только что обсуждали, это должно вернуть $proxy объект, назначенный этому конкретному ключу. Затем он пытается вызвать метод getCategory на этом объекте. Но прокси-класс не реализует такой метод, тогда как это будет работать?

Магический метод __call() приходит на помощь! Всякий раз, когда вы вызываете метод, которого не существует в классе, элемент управления передается методу __call().

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

$key содержит имя функции, которая будет вызвана — getCategory. С другой стороны, $args содержит аргументы, переданные методу, и он должен быть массивом элемента, содержащего идентификатор категории, который будет передан.

Далее, есть массив, в $arg_data, в котором хранятся ссылки на аргументы. Честно говоря, я не уверен, что код $arg instanceof Ref имеет какой-то смысл. Если кто-нибудь знает, почему он там, расскажите, я буду рад узнать.

Кроме того, он пытается проверить существование свойства $key в объекте $proxy, и это приводит к чему-то вроде этого.

Напомним, что ранее мы назначили все методы класса ModelCatalogCategory как свойства объекта $proxy, используя цикл for. Для вашего удобства я снова вставлю этот код.

Таким образом, он должен быть там, и он также должен вернуть нам вызываемую функцию! Наконец, он вызывает эту функцию, вызываемую с помощью call_user_func_array функции, передавая саму вызываемую функцию и аргументы метода.

Теперь давайте обратим наше внимание на само определение вызываемое функцией. Я возьму фрагмент из callback метода, определенного в system/engine/loader.php.

Поскольку это анонимная функция, она сохранила значения в форме переменных $registry и $route, которые ранее были переданы методу обратного вызова. В этом случае значение переменной $route должно быть catalog/category/getCategory.

Кроме того, если мы посмотрим на важный фрагмент этой функции, то увидим, что он создает экземпляр объекта ModelCatalogCategory и сохраняет его в статическом $model массиве.

И вот фрагмент, захватывающий имя метода, которое нужно вызвать с помощью $route переменной.

Таким образом, мы имеем ссылку на объект и имя метода, которое позволяет нам называть его с помощью call_user_func_array функции. Именно это делает следующий объект!

В конце метода полученный результат возвращается через $output переменную. И это еще одна часть истории!

Я намеренно игнорировал код событий pre и post, который позволяет переопределять методы основных классов OpenCart. Используя его, можно переопределить любой метод основного класса и настроить его в соответствии с потребностями. Но давайте сделаем это в течение несколько позже, так как это будет слишком много, чтобы вписаться в одну статью!

Так вот как это вообще работает. Я надеюсь, что вы должны быть более уверенны в вызовах OpenCart и их внутренней работе.

Заключение

То, что мы только что обсуждали сегодня, является одной из интересных и неоднозначных концепций в OpenCart: использование прокси-метода в рамках поддержки сокращенных соглашений для вызова методов модели. Надеюсь, статья была достаточно интересна и обогатила ваши знания OpenCart.

Автор: Sajal Soni

Источник: //code.tutsplus.com/

Редакция: Команда webformyself.

Метки:

Похожие статьи:

Комментарии Вконтакте: