Перегрузка в PHP
Поговорим о перегрузке методов и свойств в PHP, зачем и нужно ли это вообще
И сразу с ходу удар под дых - хотя в документации официального сайта PHP есть специальный раздел «Перегрузка» , это ни в коем случае не является перегрузкой. Парам-пам!
Потому что, если мы проверим определение перегрузки функции или перегрузки метода, это будет звучать примерно так:
Перегрузка функций или методов - это возможность создавать несколько функций с одним и тем же именем с разными реализациями.
Проще говоря, «перегрузка означает многократное объявление функции с другим набором параметров» . Это будет выглядеть так:
function getValue($a)
{
return $a;
}
function getValue($a, $b)
{
return $a + $b;
}
echo getValue(10); // вывод "10"
echo getValue(10, 5); // должен вывести "15"
Ну и на данный момент в PHP нет возможности сделать это. Или можно? Давай-те посмотрим.
Перегрузка в ООП
Что интересно, "Перегрузка" является одним из базовых понятий в концепции ООП, так же как и класс, объект, инкапсуляция, полиморфизм и т.д. Что касаемо PHP, в нем периодически все таки надо что-то перегружать.
Но разные люди говорят разные вещи, кто-то, что нам не нужно в принципе перегружать в PHP, кто-то, что в PHP есть только частичная поддержка перегрузки и т.д. И каждый отчасти прав, в PHP есть путь, с помощью которого вы все же можете реализовать перегрузку.
Перегрузка в PHP
Концепция перегрузки требует магических методов, суть метода заключается в создании динамических сущностей. Свойства и методы - это именно те сущности, которые и будут создаваться динамически с помощью перегрузки PHP. После создания объекта мы можем получить доступ к набору сущностей, то есть свойствам или методам, не определенных в рамках класса.
Магические методы начинаются с __ (двойное подчеркивание) и автоматически вызываются PHP. Кроме того, они всегда определяются внутри, а не вне класса. Различные магические методы: __get(), __set(), __ construct(), __destruct(), __call(), __callStatic(), __isset(), __unset(). Большинство магических методов будут запускаться в контексте объекта, за исключением метода __callStatic(), который используется в статическом контексте.
Типы перегрузки PHP
Перегрузку в PHP можно классифицировать как,
- Перегрузка свойств
- Перегрузка методов
Перегрузка свойств
Перегрузка свойств PHP позволяет нам создавать у объекта динамические свойства. Свойство, связанное с экземпляром класса и не объявленное внутри класса, считается перегруженным свойством.
Мы можем выполнять следующие операции с перегруженными свойствами в PHP.
- Установка и получение перегруженных свойств.
- Оценка настройки перегруженных свойств.
- Отмена настройки таких свойств.
- __set() - срабатывает при инициализации перегруженных свойств.
- __get() - срабатывает при использовании перегруженных свойств.
- __isset() - этот магический метод вызывается, когда мы проверяем перегруженные свойства с помощью функции isset()
- __unset() - аналогично, эта функция будет вызываться при использовании PHP unset() для перегруженных свойств.
Еще проще понять срабатывание этих методов в тот момент, когда свойства, к которым они будут применимы будут недоступны. Т.е. если мы попытаемся присвоить значение недоступному свойству, то как раз сработает __set(), либо наоборот попытка чтение недоступного свойства приведет к срабатыванию __get(). Надеюсь так будет понятнее.
Итак посмотрим на пример, который предназначен для динамического создания элементов массива свойств:
class Toys
{
private $data;
public function __set($name, $value)
{
$this->data[$name] = $value;
}
public function __get($name)
{
echo "Перегруженное свойство name = " . $this->data[$name] . "\r\n";
}
public function __isset($name)
{
if (isset($this->data[$name])) {
echo "Свойство \$$name существует.\r\n>";
} else {
echo "Свойство \$$name не существует.\r\n";
}
}
public function __unset($name)
{
unset($this->data[$name]);
echo "\$$name очищен \r\n";
}
}
$objToys = new Toys;
// сеттеры и геттеры динамических свойств
$objToys->overloaded_property = "new";
echo $objToys->overloaded_property . "\r\n";
// Операции со значениями динамических свойств
isset($objToys->overloaded_property);
unset($objToys->overloaded_property);
isset($objToys->overloaded_property);
//Перегруженное свойство name = new
//Свойство $overloaded_property существует.
//$overloaded_property очищен
//Свойство $overloaded_property не существует.
В приведенном выше примере создается динамическое свойство overloaded_property. При инициализации этого динамического свойства вызывается __set() с парой имя и значение, которая инициализируется как имя и значение элемента массива свойств класса $data.
Вдобавок к этому isset() и unset() с перегруженным свойством будут запускать магические методы __isset() и __unset(). Тут все достаточно просто, перейдем к другой перегрузке.
Перегрузка методов или функций
Если вы хотите реализовать перегрузку метода или функции в PHP, вы можете добиться этого с помощью магического метода __call() или __callStatic(). В отличие от перегрузки свойств, перегрузка метода PHP позволяет вызывать функцию как в объектном, так и в статическом контексте.
Для начала возьмем пример попроще и с явным поведением:
class Toys
{
public function __call($name, $param)
{
echo "Магический метод, вызываемый при перегрузке метода ссылкой на объект\r\n";
}
public static function __callStatic($name, $param)
{
echo "Магический метод, вызываемый при перегрузке метода со статическим доступом\r\n";
}
}
$objToys = new Toys;
$objToys->overloaded_method(); //Магический метод, вызываемый при перегрузке метода ссылкой на объект
Toys::overloaded_property(); // Магический метод, вызываемый при перегрузке метода со статическим доступом
Как видно из примера доступ к некоторому перегруженному методу с именем класса вызовет статический магический член, определенный внутри класса.
Теперь попробуем реализовать что-нибудь посложнее:
class MyClass
{
public function __call($member, $arguments)
{
$numberOfArguments = count($arguments);
if (method_exists($this, $function = $member.$numberOfArguments)) {
call_user_func_array(array($this, $function), $arguments);
}
}
private function overloaded_method1($argument1)
{
return $argument1;
}
private function overloaded_method2($argument1, $argument2)
{
return $argument1 + $argument2;
}
}
$class = new MyClass();
echo $class->overloaded_method(10); // вывод '10'
echo $class->overloaded_method(10, 5); // вывод '15'
Как видите, при вызове метода объекта overloaded_method() класса MyClass он запускает магический метод __call, поскольку вызываемый метод overloaded_method() не существует.
И далее здесь начинается магия. Как вы понимаете, у нас есть два разных метода, вызываемых overloaded_method1() и overloaded_method2() для обработки одного аргумента и двух аргументов соответственно.
Метод __call вызывает эти методы, используя функцию call_user_func_array, основанную на количестве аргументов при вызове метода overloaded_method. И вот так вы можете добиться более сложной перегрузки методов/функций в PHP.
Конечно, использовать это несколько сложно. Поскольку вам придется вручную проверять некоторые вещи и следить за тем, чтобы что-то не сломалось.
Однако, используя данный принцип и, возможно, опираясь на другие варианты использования, возможна такая форма перегрузки, при условии, что у вас есть некоторые строгие соглашения об именах в ваших функциях для их точного вызова. Как у нас в нашем примере, overloaded_method1 и overloaded_method2.
Напоследок
Конечно, стало бы намного проще, если бы PHP позволил нам несколько раз объявлять одну и ту же функцию, но с разными аргументами, не выполняя при этом разного рода магии.
Будем надеяться, что в будущих версиях PHP будет реализовываться такое поведение изначально.
Юзер26.10.2024
Привет, где можно смотреть, что планируется добавить в php, дальше, чем следующее обновление?
Сергей Мухин 28.10.2024
Привет!
Если конкретно по Перегрузке, то следить за новыми RFC)
В тех же Релизах PHP справа можно найти Что Нового в последней версии