Php классы перегрузка методов

Перегрузка

Перегрузка в PHP означает возможность динамически » создавать » свойства и методы. Эти динамические сущности обрабатываются с помощью «волшебных» методов, которые можно создать в классе для различных видов действий.

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

Все методы перегрузки должны быть объявлены как public.

Замечание:

Ни один аргумент не может быть передан по ссылке в эти «волшебные» методы.

Замечание:

Интерпретация » перегрузки » в PHP отличается от остальных объектно-ориентированных языков. Традиционно перегрузка означает возможность иметь множество одноименных методов с разным количеством или различными типами аргументов.

Список изменений

Версия Описание
5.3.0 Добавлен метод __callStatic(). Добавлено предупреждение об усилении публичной видимости и не-статичном объявлении.
5.1.0 Добавлены методы __isset() и __unset(). Добавлена поддержка для перегрузки приватных свойств с помощью __get().
5.0.0 Добавлен метод __get().

Перегрузка свойств

Метод __set() будет выполнен при записи данных в недоступные свойства.

Метод __get() будет выполнен при чтении данных из недоступных свойств.

Метод __isset() будет выполнен при использовании isset() или empty() на недоступных свойствах.

Метод __unset() будет выполнен при вызове unset() на недоступном свойстве.

Аргумент $name представляет собой имя вызываемого свойства. Метод __set() содержит аргумент $value , представляющий собой значение, которое будет записано в свойство с именем $name .

Перегрузка свойств работает только в контексте объекта. Данные магические методы не будут вызваны в статическом контексте. Поэтому данные методы не должны объявляться статичными. Начиная с версии PHP 5.3.0, при объявлении «волшебного» метода в качестве static будет показано предупреждение.

Замечание:

Возвращаемое значение метода __set() будет проигнорировано из-за способа обработки в PHP оператора присваивания. Аналогично, __get() никогда не вызовется при цепных присваиваниях, например, таких:

Пример #1 Перегрузка свойств с помощью методов __get(), __set(), __isset() и __unset()

class PropertyTest
/** Место хранения перегружаемых данных. */
private $data = array();

/** Перегрузка не применяется к объявленным свойствам. */
public $declared = 1 ;

/** Здесь перегрузка будет использована только при доступе вне класса. */
private $hidden = 2 ;

public function __set ( $name , $value )
echo «Установка ‘ $name ‘ в ‘ $value ‘\n» ;
$this -> data [ $name ] = $value ;
>

public function __get ( $name )
echo «Получение ‘ $name ‘\n» ;
if ( array_key_exists ( $name , $this -> data )) return $this -> data [ $name ];
>

$trace = debug_backtrace ();
trigger_error (
‘Неопределенное свойство в __get(): ‘ . $name .
‘ в файле ‘ . $trace [ 0 ][ ‘file’ ] .
‘ на строке ‘ . $trace [ 0 ][ ‘line’ ],
E_USER_NOTICE );
return null ;
>

/** Начиная с версии PHP 5.1.0 */
public function __isset ( $name )
echo «Установлено ли ‘ $name ‘?\n» ;
return isset( $this -> data [ $name ]);
>

/** Начиная с версии PHP 5.1.0 */
public function __unset ( $name )
echo «Уничтожение ‘ $name ‘\n» ;
unset( $this -> data [ $name ]);
>

/** Не «волшебный» метод, просто для примера. */
public function getHidden ()
return $this -> hidden ;
>
>

$obj -> a = 1 ;
echo $obj -> a . «\n\n» ;

var_dump (isset( $obj -> a ));
unset( $obj -> a );
var_dump (isset( $obj -> a ));
echo «\n» ;

echo «Давайте поэкспериментируем с private свойством ‘hidden’:\n» ;
echo «Private свойства видны внутри класса, поэтому __get() не используется. \n» ;
echo $obj -> getHidden () . «\n» ;
echo «Private свойства не видны вне класса, поэтому __get() используется. \n» ;
echo $obj -> hidden . «\n» ;
?>

Результат выполнения данного примера:

Установка 'a' в '1' Получение 'a' 1 Установлено ли 'a'? bool(true) Уничтожение 'a' Установлено ли 'a'? bool(false) 1 Давайте поэкспериментируем с private свойством 'hidden': Private свойства видны внутри класса, поэтому __get() не используется. 2 Private свойства не видны вне класса, поэтому __get() используется. Получение 'hidden' Notice: Неопределенное свойство в __get(): hidden в файле на строке 70 в на строке 29

Перегрузка методов

В контексте объекта при вызове недоступных методов вызывается метод __call().

В статическом контексте при вызове недоступных методов вызывается метод __callStatic().

Аргумент $name представляет собой имя вызываемого метода. Аргумент $arguments представляет собой числовой массив, содержащий параметры, переданные в вызываемый метод $name .

Пример #2 Перегрузка методов с помощью методов __call() и __callStatic()

class MethodTest public function __call ( $name , $arguments ) // Замечание: значение $name регистрозависимо.
echo «Вызов метода ‘ $name ‘ »
. implode ( ‘, ‘ , $arguments ). «\n» ;
>

/** Начиная с версии PHP 5.3.0 */
public static function __callStatic ( $name , $arguments ) // Замечание: значение $name регистрозависимо.
echo «Вызов статического метода ‘ $name ‘ »
. implode ( ‘, ‘ , $arguments ). «\n» ;
>
>

$obj = new MethodTest ;
$obj -> runTest ( ‘в контексте объекта’ );

MethodTest :: runTest ( ‘в статическом контексте’ ); // Начиная с версии PHP 5.3.0
?>

Результат выполнения данного примера:

Вызов метода 'runTest' в контексте объекта Вызов статического метода 'runTest' в статическом контексте

Источник

Перегрузка методов и аксессоры в PHP

С помощью перегрузки методов в PHP, можно создать метод с таким же названием, что и в базовом классе, который заменит метод базового класса при вызове.

Все методы перегрузки объявляются исключительно только как «public».

 class base_class < public function method_base() < echo 'Вызван метод "method_base" базового класса'; >> class derivative_class extends base_class < public function method_base() < echo 'Вызван метод "method_base" производного класса'; >> $_new_class = new derivative_class(); $_new_class->method_base(); 

Результатом работы будет вывод фразы «Вызван метод «method_base» производного класса».

Таким образом, метод base_class::method_base() не вызывается при обращении к объекту производного класса «derivative_class».

Однако в рамках производного класса остаётся возможность вызвать метод базового класса, обратившись к нему при помощи префикса «parent::».

Ниже будет представлен пример перегрузки метода «method_base()», при котором метод производного класса сначала вызывает метод базового класса.

 class base_class < public function method_base() < echo 'Вызван метод "method_base" базового класса'; >> class derivative_class extends base_class < public function method_base() < parent::method_base(); echo '
Вызван метод "method_base" производного класса'; > > $_new_class = new derivative_class(); $_new_class->method_base();

Результат покажет уже две строчки «Вызван метод «method_base» базового класса» и «Вызван метод «method_base» производного класса».

Таким образом, при помощи перегрузки метода можно как расширить метод базового класса, так и полностью заменить его уже новым методом.

Ниже будет продемонстрирован пример перегрузки методов с класса «mysqli»:

 class connect extends mysqli < public function __construct($_host_base = null, $_user_base = null, $_password_base = null, $_data_base = null) < parent::init(); # Перегружаем метод инициализации, чтобы установить опции; /* - Перегружаем опцию (метод) и устанавливаем таймаут соединения; */ if (!parent::options(MYSQLI_OPT_CONNECT_TIMEOUT, 5)) < die('Error: # Превышен таймаут соединения'); >/* - Прегружаем метод соединения с базой данных, с перегрузкой опции (метода) для установления кодировки ; */ if (!parent::real_connect($_host_base, $_user_base, $_password_base, $_data_base, parent::options(MYSQLI_INIT_COMMAND, 'SET NAMES utf8'))) < die('Connect DataBase Error: #'. mysqli_connect_error() .' : ('. mysqli_connect_errno() .')'); >> // Далее мы создадим свой метод в котором перегрузим метод из базового класса; public function sqlQuery($_Query) < return parent::query($_Query); >> $_Sql = new connect('localhost', 'Юзер', 'Пароль', 'База') or die('Error Class: connect'); $_Sql->sqlQuery('Запрос'); 

В примере конструктор имеет нужные нам опции, при этом из его тела происходит перегрузка методов из базового класса с помощью ключевого слова , после чего выполняются действия, специфические для класса «mysqli». Аналогичным образом могут перегружаться любые методы базового класса в производном классе «connect».

Помимо этого в PHP существует ещё два «магических» метода (аксессоры),при помощи которых можно перегрузить свойства, которые вызываются при обращении к свойству класса и при изменении его значения, — это методы «__get()» и «__set()».

Данные методы «__get()» и «__set()» позволяют легко проводить динамическое назначение свойств объектам, а в качестве параметров этим методам передаются имена свойств.

А также, метод «__set()» может получить и значение, которое присваивается указанному свойству. Приведём пример:

 class setget < // Член в котором будут храниться перегружамые данные; private $_array = array() ; /* - Выполняем запись данных в недоступные свойства */ private function __set($_Home, $_Value) < $this->_array[$_Home] = $_Value; > /* - Выполняем чтение данных из недоступных свойств */ private function __get($_Home) < return $this->_array[$_Home]; > > $class_ = new setget(); $class_->test = 'Обращение к несуществующему элементу'; echo $class_->test; 

Как видно из примера, класс «setget» перехватывает обращения к членам и создает соответствующий элемент в массиве $_array.

При попытке присвоить члену значение, создаётся новый элемент в массиве $_array.

Если член в классе уже существует, то аксессоры «__set()» и «__get()» перехватывают обращение к нему, если он имеет спецификатор доступа «private» и не перехватывают, если он имеет спецификатор «public».

Ещё существуют новый метод перегрузки «__callStatic()» который добавлен в PHP 5.3, и метод «__call». Пример:

 class callandstatic < // Общее замечание: Значение $_Home регистрозависимо; public function __call($_Home, $_arg) < echo implode(', ', $_arg) . $_Home; >public static function __callStatic($_Home, $_arg) < echo implode(', ', $_arg) . $_Home; >> $class_ = new callandstatic; $class_->_test('Вызов недоступного метода '); callandstatic::_test('Вызов недоступного статического метода '); /* * Начиная только с версии PHP 5.3 иначе будет вызвана ошибка * (Fatal error: Call to undefined method callandstatic::_test()) */ 

$_Home содержит имя метода, а $_arg массив в котором храняться параметры которые передаются из метода $_Home.

Комментировать

Однако перегружать методы можно только в процессе наследования. В одном и том же классе нельзя записать методы с одинаковыми названиями, но с разными аргументами, так как сигнатура метода не зависит от аргументов. Поддержка полиморфизма в PHP неполная.

Я извиняюсь, что придираюсь к терминологии, но полагаю, что в статье подразумевается переопределение (override), а не перегрузка (overload). Последнее подразумевает выбор одного из методов с одним и тем же названием, в зависимости от сигнатуры метода, а первое — реализацию в классе метода с такой же сигнатурой, как и в классе родителя, и выбор во время выполнения программы нужной реализации, в зависимости от конкретного типа объекта.

Источник

Перегрузка методов в php?

Я учился программировать сначала на Java, затем подвернулась работа PHP программиста и я достаточно быстро на него пересел. Однако насколько вы можете знаеть Java — язык строгой типизации, а PHP нет, отсюда у меня появились некоторые проблемы с написанием некотрых классов.
Например в PHP нет явной перегрузки методов, я предлогаю обсудить как можно найти выход из такой сютуации.

Для примера рассмотрим класс продуктов допустим в интернет магазине.

class Prodcuts < public $name; public $price; public $id; function __construct($id)< $sql = "SELECT * FROM products WHERE = mysql_query($sql); $array = mysql_fetch_array($result); $this->name = $array['name']; $this->price = $array['price']; $this->id = $id; > >

Создать новый обьект в таком сулучае можно будет так:
$objProd = new Product(1)
В конструкторе класса выбиратся всё что связанно с и обьект инициализируется.
Но в какой то момент я понял мне требуется инициализация обьекта и по другим параметрам,
нариример для такого метода:

static function create($name,$price) < $sql = "INSERT INTO poducts(name,price) VALUES ('$name','$price')"; if(mysql_query($sql))< return new Prodcuts($name,$price); >>

Тут родился вопрос перегрузки конструктора или какого то альтернативного способа инициализации обьекта.
Я знаю несколько способов и поделюсь ими свами. Буду рад если кто-то предложит ещё варианты решения этой задачи.

Cпособ №1. Использование опциональных параметров.
Переделам конструктор так:

function __construct($id=null,$name=null,$price=null)< if ( isset($name) && isset($price))< $this->name = $name; $this->price = $price; >else < $sql = "SELECT * FROM products WHERE = mysql_query($sql); $array = mysql_fetch_array($result); $this->name = $array['name']; $this->price = $array['price']; $this->id = $id; > >

тоесть мы можем не указывать параметр id
получается так:
$product = new Prodcuts(null,$name,$price);
согласитесь, это не очень красиво.

Cпособ №2. Использование функций func_num_args() и func_get_arg().

function __construct($id)< if(func_num_args()>1)< $this->name = func_get_arg(0); $this->price = func_get_arg(1); >else< $sql = "SELECT * FROM products WHERE = mysql_query($sql); $array = mysql_fetch_array($result); $this->name = $array['name']; $this->price = $array['price']; $this->id = $id; > >

Здесь мы используем две «магические» функции:
func_num_args() — возвращает колличество аргументов текущей функции,
func_get_arg() — возвращает указанный аргумент текущей функции(отсчет ведётся с ноля),
проверяем колличество указанных параметров и инициализируем объект так как нам нужно.

Способ №3. Использования для инициализации статичной функции отказ от «перегрузки» конструкторов

static public function createWithTwoParams($name,$price) < $object = new self(); $object->initTwoParams($name, $price); return $object; > protected function initTwoParams($price,$name) < $this->name = $name; $this->price = $price; >

В таком случае получается:
статичную функцию можно выполнить без создания объекта, и она вернёт нам экземпляр класса product
$product = Products::createWithTwoParams($name,$price);
Но и конструктор мы тоже сможем использовать.
$product = new Prodcuts($id);

Пусть в PHP нет перегрузки и ещё чего то, зато нетсрогая типизация позваляет вытворять то что «взрослым языкам» и не снилось, да и ктому же это очень удобно, а все проблемы с вязанные с недостатком чего-либо можно решить.

PS: мой первый пост, не судите строго.

Источник

Читайте также:  Css input pseudo class
Оцените статью