Как расширить класс php
Расширение класса PHP с помощью подклассов и создание всех функций в одном объекте
Я использую Smarty Template Engine (http://smarty.net ) на сайте, но у меня есть дополнительные, настраиваемые функции для обработки задач компиляции шаблонов.
Чтобы иметь возможность обновлять файлы инфраструктуры Smarty (например, /smarty/Smarty.class.php) и не нужно копировать и вставлять мою пользовательскую функцию в класс внутри Smarty.class.php, я подумал: «эй, давайте просто сделаем мой собственный класс и расширить класс Smarty! » Тем не менее, я не могу заставить это работать и буду признателен за любые полезные советы 🙂
Вот что я получил на данный момент:
Smarty.class.php
Файл стороннего поставщика и класс, который я не хочу трогать:
Smarty_Compiler.class.php
Другой файл и класс сторонних поставщиков, который я не хочу трогать:
Smarty.inc.php
Результат и проблема
Хорошо, я надеюсь, что мои намерения ясны из приведенных выше фрагментов кода: Я хочу объект $ умник содержать также
И потому что я используюпродолжается«для моего объявления 2 классов я думал, что это должно просто работать, используя:
Но, к сожалению, этого не происходит 🙁 Я МОГУ добавить свои пользовательские функции непосредственно в класс Smarty внутри Smarty.class.php — но это, очевидно, сделает файл не подлежащим обновлению.
Чего мне не хватает, используя мои 2 подкласса, расширяющие класс Smarty, и во время разговора с методами, объявленными в них? Или как бы вы подошли к расширению стороннего класса с помощью пользовательских / переписанных функций, не затрагивая оригинальный код?
Спасибо за любой совет!
Решение
✅ на основе этот stackoverflow-Вопрос / Ответы Я смог преодолеть свою проблему и запустить Код с моими пользовательскими классами и методами.
Решение (суммировано)
Если бы я все еще что-то пропустил или какие-либо рекомендации, я был бы рад услышать об этом 🙂
Мы принимаем к оплате:
«Подарочный сертификат» от нашего Учебного Центра – это лучший подарок для тех, кто Вам дорог! Оплате обучение и подарите Вашим родным и близким обучение по любому из курсов.
«Сертификат на повторное обучение» дает возможность повторно пройти обучение в нашем Учебном Центре со скидкой 1000 рублей!
Php как расширить класс
Расширение классов PHP
Когда речь заходит о объектно-ориентированном программировании, в целом класс выполняет определенную задачу, такую как данные пользователя удержания или управление вводом/выводом.
Когда вы разрешите сказать 1 объект, который используется для управления выходом, вы можете установить метод внутри этого объекта для управления типом вывода или как обрабатывать каждый конкретный контент, но это будет означать, что объекты единственные цель была нарушена, так как теперь она не просто отправляет контент, но также манипулирует содержимым в зависимости от его типа.
Способ, которым мы это используем, заключается в группировке набора задач в группу классов/объектов, например:
Класс вывода, очевидно, будет иметь гораздо больше методов, но только методы, связанные с выводом содержимого, такие как заголовки и т.д., а не манипуляция содержимым, тогда у вас будет что-то вроде:
и для манипулирования содержимым:
Это основные точки архитектуры, которые я соблюдаю при создании и организации многих сгруппированных классов/объектов.
PHP – расширенный __конструкция
Родительский __construct() определенный в классе b, будет запускаться автоматически, если вы создаете экземпляр дочернего класса a, если только не существует __construct() определенный в классе a.
Я не уверен, что полностью понимаю, что вы просите, но вы можете вызвать метод parent для родительского конструктора
Это единственный вариант, о котором я знаю.
Вызов parent::__construct() в a::__construct() :
Вы можете вообще опустить конструктор, если не делаете никаких конкретных действий.
PHP Как вызвать метод из расширенного класса
Пытаясь использовать объекты, которые расширяют одиночный, но чего я не могу сделать. Как вызвать метод из расширенного класса?
Как показать 13 non 12 с singleton?
задан Shkarbatov Dmitriy 01 дек. ’14 в 22:28
Как расширить класс PHP с несколькими классами
Мне было интересно, если это был способ получить то, что вы увидите, как
class main_class extends main_class
Но PHP не был счастлив. 🙁
И тогда я, хотя сам позволяет спросить StackOverflow, я уверен, что кто-то будет знать решение. Тем не менее несколько часов отладки я самостоятельно решить мою проблему, только с небольшим количеством коды.
Так вот мой решил-код:
Тогда просто запустить эту функцию, чтобы продлить main_class без перекрывая первоначальные функции, поэтому она мне запустить мои новые функции, но если мне нужно, я могу получить оригинальные функции:
$MODS_ENABLED=array(); class mod_mail <. >$MODS_ENABLED[]=new mod_mail;
Теперь давайте загружать наш класс и запустить функцию из нашей моды:
Хорошо хорошо мой мод не был для отправки электронной почты, но вместо этого перенаправляет поддомены туда псевдонимы пути, но вы понимаете концепцию, показанную здесь.
Переменные и расширение классов
korpus
злой бобёр
Не силён в ООП, поэтому столкнулся с этой особенностью только сейчас.
Оказывается, что в одном классе может существовать сразу две переменных с одним именем. Это происходит. если один класс, содержащий эту переменную, расширить другим классом, в котором определить эту же самую переменную.
Такое поведение присуще и PHP5.2 и PHP5.3.
Как можно обращаться к таким «переопределяемым» переменным, чтобы знать наверняка, что выбирается именно нужная? Я может хочу обратиться к переменной, которая определена в классе a, но хочу сделать это из класса d, который создан последовательно расширением классов a, b, c.
И как данная особенность может быть использована в ООП на PHP? Я думаю, что это может только запутать. Так, столкнувшись с этим в Yii, я был запутан.
korpus
злой бобёр
Результат скрипта в PHP5.2.4, кстати, будет такой:
object(a)#1 (1) < ["_titlerivate»]=> string(7) «a-title» > object(b)#2 (2) < ["_title
rivate»]=> string(7) «b-title» [«_title
rivate»]=> string(7) «a-title» >
$_title в объекте a = a-title
$_title в объекте b = b-title
Отличие от PHP5.3 будет в том, что в PHP5.3 var_dump() показывает, от какого класса будет существовать переменная.
В настоящее время я работаю над мини-фреймворком, и у меня возникли некоторые трудности. Я пытаюсь сделать это, чтобы укрепить мое понимание основных концепций, используемых в большинстве MVC (по крайней мере из того, что я видел). Так что да, я понимаю, что использование фреймворка может быть проще, и не все, что я делаю, идеально. Я просто пытаюсь узнать больше.
Итак, у меня есть 2 файла, с которыми я сейчас работаю.
Так что я хотел бы иметь возможность расширить BaseController с помощью FrontController. Я подумал, что расширение BaseController позволит мне добавить общие функциональные возможности ко всему моему приложению. Проблема в том, что я не уверен, как это сделать правильно. Я знаю, что мне нужно как-то «требовать» BaseController.php в FrontController.php, но я видел много разных способов, и я хочу знать, какой из них наиболее правильный.
Я попытался просто добавить ‘require_once(«/application/BaseController.php»); в начало FrontController.php, а затем расширяя класс FrontController, но это не работает (пустая страница), и из того, что я прочитал, это не лучший способ.
Я прочитал в __autoload(), но я не понимаю, как использовать его эффективно. Должен ли я просто поместить это в начало моего файла FrontController.php и расширить мой класс после этого?
Подводя итог, я хотел бы расширить свой класс FrontController (и другие будущие классы, когда это необходимо) с моим BaseController. Мне просто хотелось бы дать несколько советов о том, как эффективно выполнить эту задачу. Может даже случиться так, что я придумал эту мысль задом наперед, и если это так, пожалуйста, дайте мне знать!!
Подробно об объектах и классах в PHP
Сегодня объекты используются очень активно, хотя это трудно было предположить после выхода PHP 5 в 2005 году. Тогда я ещё мало что знал о возможностях этого языка. Пятую версию PHP сравнивали с предыдущей, четвёртой, и главным преимуществом нового релиза стала новая, очень мощная объектная модель. И сегодня, десять лет спустя, около 90% всего PHP-кода содержит объекты, не изменившиеся со времени PHP 5.0. Это убедительно говорит о том, какую роль сыграло внедрение объектной модели, неоднократно улучшавшейся на протяжении последующих лет. В этом посте я хотел бы рассказать о том, как всё устроено «под капотом». Чтобы люди понимали суть процессов — почему сделано так, а не иначе — и лучше, полнее использовали возможности языка. Также я затрону тему использования памяти объектами, в том числе в сравнении с эквивалентными массивами (когда это возможно).
Я буду рассказывать на примере версии PHP 5.4, и описываемые мной вещи справедливы для 5.5 и 5.6, потому что устройство объектной модели там почти не претерпело изменений. Обратите внимание, что в версии 5.3 всё не так хорошо с точки зрения возможностей и общей производительности.
В PHP 7, который пока ещё активно разрабатывается, объектная модель переработана не сильно, были внесены лишь незначительные изменения. Просто потому что всё и так хорошо работает, а лучшее — враг хорошего. Были добавлены возможности, не затрагивающие ядро, но здесь об этом речи не пойдёт.
В качестве демонстрации начну с синтетических бенчмарков:
Здесь объявляется простой класс с тремя атрибутами, а затем в цикле создаётся 1000 объектов этого класса. Обратите внимание, как в этом примере используется память: при создании объекта класса Foo и переменной для его хранения выделяется 262 байт динамической памяти PHP.
Давайте заменим объект на эквивалентный массив:
Вот ещё один пример:
Теперь давайте разберём, как всё это устроено в недрах PHP, подкрепив теорией практические наблюдения.
Всё начинается с классов
Внутри PHP класс представляется с помощью структуры zend_class_entry:
Важно знать ещё об одном моменте, связанном с zend_class_entry — о PHP-комментариях. Они также известны как аннотации. Это строковые переменные (в языке С — буферы char* ), которые тоже надо разместить в памяти. Для языка С, не использующего Unicode, в отличие от PHP, правило очень простое: один символ = один байт. Чем больше у вас в классе аннотаций, тем больше памяти будет использовано после парсинга.
У zend_class_entry поле doc_comment содержит аннотации класса. У методов и атрибутов тоже есть такое поле.
Пользовательские и внутренние классы
Пользовательский класс — это класс, заданный с помощью PHP, а внутренний класс задаётся либо благодаря внедрению исходного кода в сам PHP, либо с помощью расширения. Самое большое различие между этими двумя видами классов заключается в том, что пользовательские классы оперируют памятью, выделяемой по запросу, а внутренние — «постоянной» памятью.
Это означает, что когда PHP заканчивает обработку текущего HTTP-запроса, он убирает из памяти и уничтожает все пользовательские классы, готовясь к обработке следующего запроса. Этот подход известен под названием «архитектура без разделения ресурсов» (the share nothing architecture). Так было заложено в PHP с самого начала, и изменять это пока не планируется.
Итак, каждый раз при формировании запроса и парсинге классов происходит выделение памяти для них. После использования класса уничтожается всё, что с ним связано. Так что обязательно используйте все объявленные классы, в противном случае будет теряться память. Применяйте автозагрузчики, они задерживают парсинг/объявление во время выполнения, когда PHP нужно задействовать класс. Несмотря на замедление выполнения, автозагрузчик позволяет грамотно использовать память, поскольку он не будет запущен, пока действительно не возникнет потребность в классе.
С внутренними классами всё иначе. Они размещаются в памяти постоянно, вне зависимости от того, использовали их или нет. То есть они уничтожаются только тогда, когда прекращается работа самого PHP — после завершения обработки всех запросов (подразумеваются веб SAPI, например, PHP-FPM). Поэтому внутренние классы более эффективны, чем пользовательские (в конце запроса уничтожаются только статические атрибуты, больше ничего).
Обратите внимание, что даже при кешировании опкодов, как OPCache, создание и уничтожение класса осуществляется при каждом запросе, как и в случае с пользовательскими классами. OPCache просто ускоряет оба этих процесса.
Как вы заметили, если активировать много PHP-расширений, каждое из которых объявляет много классов, но при этом использовать лишь небольшое их количество, то теряется память. Помните, что PHP-расширения объявляют классы во время запуска PHP, даже если в последующих запросах эти классы использоваться не будут. Поэтому не рекомендуется держать расширения активными, если они не применяются в данный момент, иначе вы будете терять память. Особенно если эти расширения объявляют много классов — хотя они могут забить память и чем-нибудь другим.
Классы, интерфейсы или трейты — без разницы
Не слишком хорошо, что здесь используется 912 байт всего лишь для декларирования интерфейса BarException.
Привязка класса
Многие разработчики не вспоминают о привязке класса, пока не начинают задавать вопросом, а как же всё устроено на самом деле. Привязку класса можно описать как «процесс, в ходе которого сам класс и все связанные с ним данные подготавливаются для полноценного использования разработчиком». Этот процесс очень прост и не требует много ресурсов, если речь идёт о каком-то одном классе, не дополняющем другой, не использующем трейты и не внедряющим интерфейс. Процесс привязки для таких классов полностью протекает во время компиляции, а в ходе выполнения ресурсы на это уже не тратятся. Обратите внимание, что речь шла привязке класса, задекларированного пользователем. Для внутренних классов тот же самый процесс выполняется, когда классы зарегистрированы ядром или расширениями PHP, как раз перед запуском пользовательских скриптов — и делается это лишь один раз за всё время работы PHP.
Всё сильно усложняется, если речь заходит о внедрении интерфейсов или наследовании классов. Тогда в ходе привязки класса у родительских и дочерних объектов (будь то классы или интерфейсы) копируется абсолютно все.
Тут добавить нечего, простой случай.
Для каждой из таблиц функций (методов) используется do_inherit_method :
Что касается наследования, то здесь, в принципе, всё то же самое, что и при внедрении интерфейса. Только вовлечено ещё больше «участников». Но хочу отметить, что если PHP уже знает о классе, то привязка осуществляется во время компилирования, а если не знает — то во время выполнения. Так что лучше объявлять так:
Кстати, рутинная процедура привязки класса может привести к очень странному поведению:
В первом варианте привязка класса В отложена на время выполнения, потому что когда компилятор доходит до объявления этого класса, он ещё ничего не знает о классе А. Когда начинается выполнение, то привязка класса А происходит без вопросов, потому что он уже скомпилирован, будучи одиночным классом. Во втором случае всё иначе. Привязка класса С отложена на время выполнения, потому что компилятор ещё ничего не знает о В, пытаясь скомпилировать его. Но когда во время выполнения начинается привязка класса С, то он ищет В, который не существует, поскольку не скомпилирован по причине того, что В является дополнением. Вылетает сообщение “Class B doesn’t exist”.
Объекты
Итак, теперь мы знаем, что:
Теперь поговорим об объектах. В первой главе показано, что создание «классического» объекта («классического» пользовательского класса) потребовало очень мало памяти, около 200 байт. Всё дело в классе. Дальнейшая компиляция класса тоже потребляет память, но это к лучшему, потому что для создания одиночного объекта требуется меньше байт. По сути, объект представляет собой крохотный набор из крохотных структур.
Управление методами объекта
Вы могли заметить интересную вещь, посмотрите на первые строки:
Во время компиляции функции/метода происходит немедленный перевод в нижний регистр. Вышеприведённая функция BAR() превращается в bar() компилятором при добавлении метода таблице классов и функций.
В приведённом примере первый вызов статический: компилятор вычислил key для строковой “bar”, а когда приходит время вызова метода, ему нужно делать меньше работы. Второй вызов уже динамический, компилятор ничего не знает о “$b”, не может вычислить key для вызова метода. Затем, во время выполнения, нам придётся перевести строковую в нижний регистр и вычислить её хеш ( zend_hash_func() ), что не лучшим образом сказывается на производительности.
Управление атрибутами объекта
Вот что происходит:
Так что, создавая объект, мы «всего лишь» создаём структуру zend_object весом 32 байта:
Далее движок создаёт вектор признаков нашего объекта:
Вероятно, у вас возникли два вопроса:
Пока вы не пишете в объект, его потребление памяти не меняется. После записи он занимает уже больше места (пока не будет уничтожен), поскольку содержит все записанные в него атрибуты.
Объекты, ведущие себя как ссылки благодаря хранилищу объектов
Объекты не являются ссылками. Это демонстрируется на маленьком скрипте:
Все сейчас скажут, что «в PHP 5 объекты являются ссылками», об этом упоминает даже официальный мануал. Технически это совершенно неверно. Тем не менее, объекты могут вести себя так же, как и ссылки. Например, когда вы передаёте переменную, являющуюся объектом функции, эта функция может модифицировать тот же объект.
object(MyClass)#1 (0) < >/* #1 is the object handle (number), it is unique */
Когда мы вызываем метод, движок изменяет область видимости:
Вот так можно получать доступ к приватным членам объектов, не принадлежащим вам, но являющимся дочерними по отношению к вашей текущей области видимости:
Эта особенность стала причиной большого количества баг-репортов от разработчиков. Но так устроена объектная модель в PHP — на самом деле, мы задаём область видимости на основе не объекта, а класса. В случае с нашим классом “Foo”, вы можете работать с любым приватным Foo любого другого Foo, как показано выше.
О деструкторе
Деструкторы опасны, не полагайтесь на них, поскольку PHP их не вызывает даже в случае фатальной ошибки:
А что насчёт порядка вызова деструкторов в том случае, если они всё-таки вызываются? Ответ хорошо виден в коде:
Здесь продемонстрированы три стадии вызова деструктора:
PHP не вызывает деструкторы в случае возникновения какой-либо фатальной ошибки. Дело в том, что в этом случае Zend работает нестабильно, а вызов деструкторов приводит к выполнению пользовательского кода, который может получить доступ к ошибочным указателям и, в результате, к падению PHP. Уж лучше сохранять стабильность системы — поэтому вызов деструкторов и блокируется. Возможно, в PHP 7 что-то и поменяется.
Суммируя вышесказанное: не доверяйте деструкторам критически важный код, например, управление механизмом блокировки (lock mechanism), поскольку PHP может и не вызвать деструктор или вызвать его в неконтролируемой последовательности. Если всё-таки важный код обрабатывается деструктором, то как минимум самостоятельно контролируйте жизненный цикл объектов. PHP вызовет деструктор, когда refcount вашего объекта упадёт до нуля, а это значит, что объект больше не используется и его можно безопасно уничтожить.