PHP 5276 ~ 5 мин.

Перегрузка в PHP

Перегрузка в 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 будет реализовываться такое поведение изначально.


Что думаешь?

Дмитрий29.03.2023

классный сайт! а перегрузка в php отвратная(

Сергей Мухин 29.03.2023

Спасибо) Она своеобразная)
Но да, к сожалению пока, это совсем не так как в тех же Java/Kotlin/C#
Но и тот же Python (хотя у него своя магия тоже) и Golang тоже пока не имеют полноценной перегрузки методов

Категории
  • PHP 67
  • Заметки 18
  • Безопасность 4
  • Флуд 2
  • Nginx 2
  • ИТ новости 2
  • Видео 1
  • Docker 1
  • Roadmap 1
  • Архитектура 0

Хочешь поддержать сайт?

Делаем из мухи слона

sergeymukhin.com

персональный блог о веб-разработке от Сергея Мухина. Блог был основан в 2018 году, и собирался уделять основное внимание последним тенденциям, учебным пособиям, а также советам и рекомендациям, позволяющим начинающим девелоперам встать быстрее на правильную дорогу веб разработки, но что-то пошло не так 😃

Релизы PHP 8.4

Дата Релиз
4 Июля 2024 Альфа 1
18 Июля 2024 Альфа 2
1 Августа 2024 Альфа 3
13 Августа 2024 Feature freeze
15 Августа 2024 Бета 1
29 Августа 2024 Бета 2
12 Сентября 2024 Бета 3
26 Сентября 2024 RC 1
10 Октября 2024 RC 2
24 Октября 2024 RC 3
7 Ноября 2024 RC 4
21 Ноября 2024 GA

Что нового?