php переопределить константу в дочернем классе
Переопределение CONST и STATIC
Можно ли в дочерних классах переопределять свойства класса, объявленные в родительском, как CONST или static?
Пожалуйста, в случае, если переопределение возможно, поясните с архитектурной точки зрения, на сколько это не правильно и к чему приведёт?
Всем, кто откликнется на вопрос, заранее огромное спасибо!
Помощь в написании контрольных, курсовых и дипломных работ здесь.
static const
объясните, пожалуйста, вот такую странную конструкцию (накопал в старой проге): после #include.
static const?
если мне нужна константа в классе, как ее лучше объявить со static или без? разница будет только в.
static и const
static void A(); Что дает этот статик? Что он вообще дает? int A() const; Что дает конст в.
Jewbacabra, а как тогда назвать такую ситуацию?
Не переопределили, а создали новую константу.
На static будет лучше видно
Логично.
Но тогда получается в PHP вообще нет возможности переопределения.
По аналогии если переписать на объекты:
Обращаясь к разным классам вызываются разные методы, хоть мы его и переопределили.
А следующий пример собственно доказывает, что мы не переопределили, а создали новый метод.
Особенности реализации классов в PHP
Видимость
В PHP есть три спецификатора доступа: private ( закрытый ), protected ( защищенный ) и public ( общедоступный ).
Private — члены класса могут быть доступны только внутри самого класса.
Protected — члены класса могут быть доступны только внутри самого класса и его дочерних классах.
Public — члены PHP class могут быть доступны из любого места: снаружи класса, внутри самого класса и из его дочерних классов.
Наследование
Наследование является одним из наиболее важных аспектов объектно-ориентированного программирования. Оно позволяет классу наследовать элементы из другого класса. Понимание наследования без примера может быть довольно сложно, поэтому давайте начнем с одного из них.
Давайте посмотрим на пример:
Очень простой класс. Тем не менее, « some sort of animal » ( какое-то животное ) не очень конкретно, поэтому создадим дочерний класс для собаки:
Вы увидите, что и name, и функция Greet() по-прежнему есть, но они также по-прежнему слишком анонимны. Изменим это, написав конкретную версию функции Greet() для нашего класса Dog :
Абстрактные классы
Если вы этого не сделаете, PHP выдаст сообщение об ошибке. Тем не менее, абстрактные классы могут также содержать неабстрактные методы, что позволяет реализовать основные функциональные возможности в абстрактном классе. Давайте посмотрим на примере. Вот это абстрактный класс:
После этого мы добавляем строку к результату, чтобы выяснить, с каким типом животного мы имеем дело. Попробуем использовать этот новый класс:
Статические классы
PHP class может быть реализован более одного раза, поэтому значения, которые он содержит, уникальны для экземпляра, а не для самого класса. Это означает, что вы не можете использовать методы или переменные в классе без создания экземпляра, но есть исключение из этого правила. Переменные и методы в одном классе могут быть объявлены как static ( также называемые shared – «общие» ). Это означает, что они могут быть использованы без создания экземпляра класса.
Поскольку переменная класса может быть доступна без конкретного экземпляра, будет только одна версия этой переменной. Другим следствием является то, что статический метод не может получить доступ к нестатическим переменным и методам, так как они требуют экземпляр класса.
В предыдущей части мы написали класс пользователя. Давайте расширим его некоторой статической функциональностью:
Константы класса
Константа — это переменная, которая никогда не может быть изменена. Когда вы объявляете константу, вы присваиваете ей значение, и после этого ее значение никогда не изменится. Простые переменные проще в использовании, но в некоторых случаях константы более предпочтительны. Например, в качестве сигнала для других программистов ( или для вас ), если забудете, что это конкретное значение не должно изменяться во время выполнения.
PHP class const просты как обычные константы, за исключением того, что они объявляются в классе и доступны через этот конкретный класс. Так же, как со статическими членами, нужно использовать оператор двойное двоеточие, чтобы получить доступ к константе класса. Вот простой пример:
Ключевое слово “final”
Окончательный (final) класс может выглядеть следующим образом:
Если необходимо, оба могут быть объединены, но они также могут быть использованы независимо друг от друга, как показано в приведенных выше примерах.
Php переопределить константу в дочернем классе
Константы класса могут быть переопределены дочерним классом.
Обратите внимание, что константы класса задаются один раз для всего класса, а не отдельно для каждого созданного объекта этого класса.
Пример #1 Объявление и использование константы
class MyClass
<
const CONSTANT = ‘значение константы’ ;
Пример #2 Пример использования ::class с пространством имён
namespace foo <
class bar <
>
echo bar ::class; // foo\bar
>
?>
Пример #3 Пример констант, заданных выражением
Пример #4 Модификаторы видимости констант класса, начиная с PHP 7.1.0
Результат выполнения данного примера в PHP 7.1:
Начиная с PHP 7.1.0 для констант класса можно использовать модификаторы области видимости.
User Contributed Notes 21 notes
it’s possible to declare constant in base class, and override it in child, and access to correct value of the const from the static method is possible by ‘get_called_class’ method:
abstract class dbObject
<
const TABLE_NAME = ‘undefined’ ;
class dbPerson extends dbObject
<
const TABLE_NAME = ‘persons’ ;
>
class dbAdmin extends dbPerson
<
const TABLE_NAME = ‘admins’ ;
>
echo dbPerson :: GetAll (). «
» ; //output: «SELECT * FROM `persons`»
echo dbAdmin :: GetAll (). «
» ; //output: «SELECT * FROM `admins`»
As of PHP 5.6 you can finally define constant using math expressions, like this one:
class MyTimer <
const SEC_PER_DAY = 60 * 60 * 24 ;
>
Most people miss the point in declaring constants and confuse then things by trying to declare things like functions or arrays as constants. What happens next is to try things that are more complicated then necessary and sometimes lead to bad coding practices. Let me explain.
A constant is a name for a value (but it’s NOT a variable), that usually will be replaced in the code while it gets COMPILED and NOT at runtime.
So returned values from functions can’t be used, because they will return a value only at runtime.
Arrays can’t be used, because they are data structures that exist at runtime.
One main purpose of declaring a constant is usually using a value in your code, that you can replace easily in one place without looking for all the occurences. Another is, to avoid mistakes.
Think about some examples written by some before me:
1. const MY_ARR = «return array(\»A\», \»B\», \»C\», \»D\»);»;
It was said, this would declare an array that can be used with eval. WRONG! This is just a string as constant, NOT an array. Does it make sense if it would be possible to declare an array as constant? Probably not. Instead declare the values of the array as constants and make an array variable.
2. const magic_quotes = (bool)get_magic_quotes_gpc();
This can’t work, of course. And it doesn’t make sense either. The function already returns the value, there is no purpose in declaring a constant for the same thing.
3. Someone spoke about «dynamic» assignments to constants. What? There are no dynamic assignments to constants, runtime assignments work _only_ with variables. Let’s take the proposed example:
Conclusion: Don’t try to reinvent constants as variables. If constants don’t work, just use variables. Then you don’t need to reinvent methods to achieve things for what is already there.
I think it’s useful if we draw some attention to late static binding here:
class A <
const MY_CONST = false ;
public function my_const_self () <
return self :: MY_CONST ;
>
public function my_const_static () <
return static:: MY_CONST ;
>
>
class B extends A <
const MY_CONST = true ;
>
const can also be used directly in namespaces, a feature never explicitly stated in the documentation.
# foo.php
namespace Foo ;
const BAR = 1 ;
?>
# bar.php
require ‘foo.php’ ;
var_dump ( Foo \ BAR ); // => int(1)
?>
class a <
const CONST_INT = 10 ;
public function getSelf () <
return self :: CONST_INT ;
>
class b extends a <
const CONST_INT = 20 ;
public function getSelf () <
return parent :: getSelf ();
>
Наследование в объектно-ориентированном программировании PHP
Этот урок мы посвятим одной из ключевых тем объектно-ориентированного программирования – теме наследования. Благодаря реализации наследования мы можем организовать связь классов по принципу родительский-дочерний и добавлять дополнительную функциональность в разрабатываемые приложения без необходимости дублирования целых блоков кода.
Что такое наследование?
В объектно-ориентированном программировании наследование позволяет нам создать класс, который наследует функциональность и может использовать свойства и методы от другого класса. Это полезно, когда мы хотим создать класс, который расширяет функциональность исходного класса, не нарушая существующий код, который использует исходный класс.
Эту связь обычно описывают с помощью терминов «родительский» и «дочерний». Класс, от которого мы наследуем, называется базовым классом, суперклассом или родительским классом. Класс, который наследует функциональность, называется подклассом или дочерним классом. В наследовании у нас есть родительский класс со своими собственными методами и свойствами, а также дочерний класс (или классы), которые унаследуют все общедоступные и защищенные свойства и методы родительского класса. Кроме того, у них могут быть свои свойства и методы.
Используя наследование, мы можем создать повторно используемый фрагмент кода, который мы пишем только один раз в родительском классе и используем снова столько, сколько нам нужно в дочерних классах.
Как наследовать от другого класса?
Существующий класс готов к наследованию, нам не нужно делать с ним ничего особенного. Этот класс называется базовым классом, суперклассом или родительским классом.
Синтаксис
Пример
Результат выполнения кода:
Собственные методы и свойства дочернего класса
Так же, как дочерний класс может использовать свойства и методы своего родительского класса, он также может иметь собственные свойства и методы. Однако, хотя дочерний класс может использовать код, унаследованный от родительского, родительскому классу не разрешается использовать код дочернего класса.
Пример
Результат выполнения кода:
Наследование и модификатор защищенного доступа
В предыдущем уроке мы узнали, что можем использовать модификатор публичного доступа, чтобы разрешить доступ к методам и свойствам класса как внутри, так и за его пределами. Мы также узнали, что те методы и свойства, которые являются приватными, могут использоваться только внутри класса.
Как вы думаете, что может случиться, когда мы попытаемся вызвать приватный метод или свойство извне класса?
Пример
Результат выполнения кода:
Пример
Результат выполнения кода:
Сказанное выше относится и к методам:
Пример
Результат выполнения кода:
Публичный метод message() дочернего класса SportsCar имеет доступ к методу intro() (который защищен) родительского класса.
Переопределение родительских свойств и методов
Так же, как дочерний класс может иметь свои собственные свойства и методы, он может переопределять свойства и методы родительского класса. Когда мы переопределяем свойства и методы класса, мы переписываем метод или свойство (с использованием того же имени), которое существует в родительском элементе, снова в дочернем, но присваиваем ему другое значение или код.
Посмотрите на пример ниже. Методы __construct() и intro() в дочернем классе (SportsCar) переопределят методы __construct() и intro() в родительском классе (Car):
Пример
Результат выполнения кода:
Ключевое слово final
Ключевое слово final может быть использовано для предотвращения наследования класса или для предотвращения переопределения метода.
В приведенном ниже примере мы объявляем класс Car как final, чтобы предотвратить наследование класса, но все же пытаемся его наследовать. В результате мы получим ошибку:
Пример
Результат выполнения кода:
В следующем примере ключевое слово final испольуется для предотвращения переопределение метода:
Пример
Результат выполнения кода:
Заключение
Мы используем наследование, чтобы уменьшить дублирование кода за счет использования кода из родительского класса в дочерних классах. В этом уроке мы изучили один из принципов объектно-ориентированного программирования — концепцию наследования. Мы используем наследование, чтобы уменьшить дублирование кода, используя код родительского класса в дочерних классах. Щелкните здесь, чтобы попрактиковаться в предмете.
PHP, статические переменные внутри методов класса и история одного бага
Вообще я разработчик фронтенда. Но порой приходится работать и с серверной частью. Команда у нас небольшая, и когда все настоящие бэкенд-программисты заняты, бывает быстрее реализовать какой-то метод самому. А иногда мы садимся вместе поработать над задачами, чтобы не терять времени на перегон коммитов туда-сюда. Недавно во время одного из таких раундов парного программирования мы с товарищем по команде столкнулись с багом, который меня так впечатлил, что я решил с вами поделиться.
Итак, когда после обеда я подошёл к своему коллеге Роману parpalak, он как раз закончил приводить в порядок юнит-тесты, и запустил всю пачку. Один из тестов выкинул исключение и упал. Ага, подумали мы, сейчас исправим баг. Запустили тест в одиночестве, вне пакета, и он прошёл успешно.
Прежде чем сбросить с себя послеобеденную дремоту, мы запустили Codeception ещё несколько раз. В пакете тест падал, в одиночку проходил, в пакете падал…
Фаталка Call to private method вылетала из метода, преобразующего объект сущности в массив для отправки клиенту. Недавно механизм этого процесса немного изменился, но ещё не все классы отрефакторили, поэтому в методе стоит проверка, переопределён ли метод, возвращающий список необходимых полей (это старый способ), в дочернем классе. Если нет, список полей формируется через рефлексию (это новый способ), и вызываются соответствующие геттеры. В нашем случае один из геттеров был объявлен как private, и, соответственно, недоступен из базового класса. Всё это выглядит примерно так:
— А что, рефлексия такая тяжёлая операция? — спросил я.
— Ну да, — кивнул Роман.
— Как такое может быть? — спросил я. — Статическая переменная внутри метода шарится при наследовании? Почему тогда мы раньше этого не заметили?
Роман был озадачен не меньше моего. Пока я ходил за кофе, он набросал небольшой юнит-тест с имитацией нашей иерархии классов, но он не падал. Мы что-то упускали из виду. Статическая переменная вела себя неправильно, не так, как мы ожидали, но не во всех случаях, и мы не могли понять, почему. Гугление по запросу «php static variable inside class method» не давало ничего путного, кроме того, что статические переменные — это нехорошо. Well, duh!
Теперь Роман пошёл за кофе, а я в задумчивости открыл PHP-песочницу и написал самый простой код:
простой пример 1
простой пример 2
простой пример 3
Вот оно! Роман как раз вернулся, и я, довольный собой, продемонстрировал свои наработки. Ему понадобилось всего несколько нажатий на клавиатуру в PHPStorm, чтобы отрефакторить участок со статической переменной в отдельный метод:
простой пример 4
В итоге мы объявили метод hasOriginalClientProps как protected и снабдили пространным комментарием.
Анализ
Время не ждало, и мы перешли к дальнейшим задачам, но всё же такое поведение озадачивало. Я решил разобраться, почему же PHP ведёт себя именно таким образом. В документации не удалось нарыть ничего, кроме неясных намёков. Ниже я попробую восстановить картину происходящего, основываясь на вдумчивом чтении PHP Internals Book, PHP Wiki, изучении исходников и информации о том, как реализуются объекты в других языках программирования.
Лично мне такое копирование показалось довольно тяжеловесным. Видимо, разработчики PHP подумали так же и отказались от копирования для приватных методов. Ведь они же всё равно не видны из дочерних и родительских классов! Вон, мы даже фаталку в самом начале рассказа словили из-за этого. Поэтому приватный метод существует в единственном экземпляре по всей иерархии классов, и статические переменные в нём тоже существует в единственном контексте. Поэтому и не заработал пример 4.
Такое поведение повторяется на всех версиях PHP, которые я попробовал в песочнице, начиная с мохнатой 5.0.4.
Почему же баг в коде нашего проекта раньше никак не давал о себе знать? Видимо, сущности редко создавались разнотипными группами, а если и создавались — то рефакторили их одновременно. А вот при прогоне тестов в один запуск скрипта попали два объекта, работающие через разные механизмы, и один из них испортил другому состояние.
Выводы
(ведь в каждой серьёзной статье должны быть выводы)
На этой воодушевляющей ноте я прощаюсь с вами. Надеюсь, что эта статья поможет кому-то избежать тех граблей, на которые наступила мы. Спасибо за внимание!