Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

См. также - Объектно-ориентированное программирование (ООП) в PHP Интерфейсы, классы,

Лекция



Это окончание невероятной информации про объектно-ориентированное программирование.

...

образом можно сократить до создания ста объектов и двухсот одного вызова методов:

$relatedObject = $myObject->getProperty('relatedObject');
for($i = 0; $i < 100; $i++)
$relatedObject->getAncestor($i)->update();

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

В следующих версиях PHP, скорее всего, можно ожидать расширения подобного подхода и к обычным массивам. Если они, конечно, еще останутся - объекты имеют тенденцию захватывать все больше и больше функциональности :-). Тогда, возможно, будет доступна следующая конструкция: print ((new ServerEnvironment()).getServerVariables())['REQUEST_URI'].

Инициализация переменных класса вне конструктора

Начальное значение переменной класса теперь можно указать непосредственно при ее объявлении. Однако, ее значение может быть только примитивного типа, т.е. строкой или числом. Тем не менее, этот метод является единственно возможным для задания значения статической переменной класса. Например:

class MathUtils {
static private pi = 3.1415926;
...
}

По другому pi определить невозможно, поскольку для статических переменных не существует "статического" конструктора.

Статические методы класса

Статические методы класса могут быть вызванны непосредственно у класса, а не через его один из его объектов. Соответственно, указатель $this в статических методах недоступен.

Фактически, объявление класса со статическими методами является, в большей мере, методом группировки функций и общих для них констант и переменных. Например, столь известные в PHP функции соединения с MySQL можно было бы оформить в виде класса MySQL:

interface DatabaseInterface {
static function connect($host, $user, $password);
static function select_db($database);
static function query($query);
static function fetch_array();
static function free_result($result);
static function close($link);
}

class MySQL implements DatabaseInterface {
static CLIENT_COMPRESS = 1;
static CLIENT_IGNORE_SPACE = 2;

...

static function connect($host, $user, $password) {
...
}

static function select_db($database) {
...
}
}

Применение такого подхода гарантирует, что все классы доступа к базе данных будут реализовывать один интерфейс (заменяемость), уменьшает вероятность конфликтности имен, упрощает существование нескольких версий класса доступа к базе и т.д.

instanceof оператор

Новый опреатор "проверяемый объект instanceof проверяемый класс" позволяет проверить, попадает ли проверяемый класс в список дерева наследования класса, экземпляром которого является проверяемый объект. На примере это выглядит так:

interface Editable {
function startEdit();
function endEdit();
}

class Control {
function getValue() {
//...
}
}

class EditableControl extends Control implements Editable {
function startEdit() {
//...
}
function endEdit() {
//...
}
}

$c = new Control();
$ec = new EditableControl();

print '$c instanceof Editable = ' . ($c instanceof Editable ? 'true' : 'false') . '
';
print '$c instanceof Control = ' . ($c instanceof Control ? 'true' : 'false') . '
';
print '$c instanceof EditableControl = ' . ($c instanceof EditableControl ? 'true' : 'false') . '
';
print '$ec instanceof Editable = ' . ($ec instanceof Editable ? 'true' : 'false') . '
';
print '$ec instanceof Control = ' . ($ec instanceof Control ? 'true' : 'false') . '
';
print '$ec instanceof EditableControl = ' . ($ec instanceof EditableControl ? 'true' : 'false');

Результатом работы этого кода будет:

$c instanceof Editable = false
$c instanceof Control = true
$c instanceof EditableControl = false
$ec instanceof Editable = true
$ec instanceof Control = true
$ec instanceof EditableControl = true

Таким образом, для $c instanceof возвращает true только для класса Control, для $ec instanceof вернет true только для Editable, Control, EditableControl. Для null всегда возращается false.

Статичекие переменные функций

Переменные внутри функции могут быть объявленны как static. Static переменная функции - это общая переменная для всех вызовов этой функции. Static переменная по смыслу примерно равна глобальной переменной, используемой только внутри функции.

Необязательные передающиеся по ссылке параметры функций

Передающиеся по ссылке параметры в PHP4 не могут иметь default значение. Это приводит к невозможности сделать функцию с необязательным объектным параметром. Но общественность требовала и в PHP5 появилась возможность задать для объектного параметра значение по умолчанию. Надо заметить, что возможно единственное значение по умолчанию для таких параметров - null.

Пример использования:

class Unrequired {
...
}

function myFunction(Unrequired $param = null) {
...
}

myFunction();
myFunction(new Unrequired());

Функция-событие при создании объекта неизвестного класса (__autoload())

PHP не держит все приложение в памяти. Более того, для каждой страницы он заново подгружает все файлы с кодом и преобразует в удобную для выполнения форму. Хорошо помогают различные акселераторы PHP кода, которые сохраняют в памяти непосредственно преобразованный в исполняемый код php-страницу. Но даже в случае использования такого оптимизатора нежелательно подключать к скрипту все файлы с классами и функциями, которые могут понадобится, но реально не используются. Настройка подключение только необходимых классов к каждой конкретной странице - занятие, требующее большой аккуратности и вызывающее большое желание это каким-то образом автоматизировать.

Возможно, именно поэтому и была введенна функция-событие с названием __autoload(), которая срабатывает при попытке обращения к неизвестному классу или интерфейсу. Под обращением понимается попытка создания объекта класса, создание класса-потомка на основе класса, создание класса, реализующего интерфейс.

Еще одна проблема, которую снимает __autoload - это размещение включений файлов в порядке иерархии наследования. Например, если MyClass1 находится в файле MyClass1.php, a MyClass2 - в файле MyClass2.php и MyClass2 extends MyClass1, то с помощью include их надо подключать только в порядке inlude('MyClass1.php'); include('MyClass2.php'); Когда 2 файла - не страшно. Но когда их несколько десятков - это уже сложнее.

И, наконец, пример использования __autoload:

test.php ============================
function __autoload($name) {
include_once('classes/' . $name . '.php');
}

$t = new Textbox();

Control.php =========================
class Control {
// ...
}

Textbox.php =========================
class Textbox extends Control {
// ...
}

При попытке создания Textbox будет загружен файл Textbox.php. Поскольку Textbox extends Control, тут же будет загружен Control.php.

Функции-события при обращении к свойству класса (__get(), __set())

Функции __get и __set могут рассматриваться как возможность реализации свойств, аналогичным свойствам в .NET, VBScript (ASP) или VB. Но в отличие от перечисленных языков (технологий), в PHP __get и __set выполняются для всех (!) свойств. Например:

ASP
Class MyClass
Property Let Value(NewValue)
...
End Property

Property Get Value()
...
End Property

Property Let State(NewValue)
...
End Property

Property Get State()
...
End Property
End Class

PHP
class MyClass {
function __get($name) {
switch($name) {
case 'Value':
...
break;
case 'State':
...
break;
}
}

function __set($name, $value) {
switch($name) {
case 'Value':
...
break;
case 'State':
...
break;
}
}
}

Вызов методов __get() и __set() при обращении к свойству происходит только если переменной класса с таким именем не существует. Если она сущеструет, то в результате обращения из основной программы можно получить либо ошибку (если переменная private или protected), либо, собственно, переменную (если она public).

Цепочки свойств ($myObj->parent->value) работают корректно. Пример:

class Node {
private $mValue = 1;
private $mParent;

function __get($name) {
switch($name) {
case 'Value':
return $this->mValue;
case 'Parent':
return $this->mParent;
}
}

function __set($name, $value) {
switch($name) {
case 'Value':
$this->mValue = $value;
break;
case 'Parent':
$this->mParent = $value;
break;
}
}
}

$n1 = new Node();
$n2 = new Node();
$n2->Parent = $n1;
$n1->Value = 2;
print $n2->Parent->Value; // Выводит 2.

Функция-событие при обращении к методу класса (__call())

Функция-событие __call(), возможно, введенна вместе с __get() и __set(). Скорее всего эта функция найдет свое применение в дальнейшем. Например, она может применяться для эмуляции перегрузки методов:

class SpecialItem {
//...
}

class GeneralItem {
//...
}

class Processor {
function processSpecialItem(SpecialItem $item) {
//...
}

function processGeneralItem(GeneralItem $item) {
//...
}

function __call($method, $attributes) {
if ($method == 'process' && count($attributes) == 1) {
if ($attributes instanceof GeneralItem)
$this->processGeneralItem($attributes );
elseif ($attributes instanceof SpecialItem)
$this->processSpecialItem($attributes );
}
}
}

$p = new Processor();
$p->process(new GeneralItem()); //processGeneralItem would be called.
$p->process(new SpecialItem()); //processSpecialItem would be called.

Итерация по свойствам класса

Все переменные класса, доступные в текущем контексте, могут быть перебранны циклом foreach. Такая итерация по свойствам класса может очень пригодится при клонировании объектов. Например, если необходимо создать клон объекта с большим количеством переменных класса, то можно сделать примерно так:

class Node {
private $value;
private $parent;
...
private $type;

function __clone() {
foreach ($that as $propertyName => $propertyValue) {
$this->$propertyName = $propertyValue;
}
}

function setParent($value) { $this->parent = $value; }
function getParent() { return $this->parent; }
function setValue($value) { $this->value = $value; }
function getValue() { return $this->value; }
...
function setType($value) { $this->type = $value; }
function getType() { return $this->type; }
}

$myNode = new Node();
$myNode->setValue(10);
$myNextNode = $myNode->__clone();
print $myNextNode->getValue();

Простой цикл очень хорошо заменяет большое количество присваиваний и избавляет от необходимости синхронизировать присваивания при клонировании со списком всех переменных класса. Очевидным образом, эта итерация не может быть применена к свойствам класса, реализованных через __get()/__set() функции.

Изменение стандартной итерации по свойствам

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

Для введения дополнительных сущностей (классов), позволяющих итерацию по своим элементам, предусмотренно 2 интерфейса: IteratorAggregate и Iterator.

interface IteratorAggregate {
function getIterator(); // возвращает массив или объект
}

IteratorAggregate может использоваться, когда данные для итерации можно предоставить в одной из стандарных конструкций PHP, позволяющих итерацию: массива или объекта, реализующего Iterator.

Пример использования IteratorAggregate с итерацией по элементам массива:

/**
Замечание:
Этот пример в PHP5 beta 3 не работает.
Тем не менее, в документации заявленно, что getIterator()
может возвращать массив или объект, реализующий Iterator.
Так что к release, надеюсь, исправят.
*/
class Control implements IteratorAggregate {
private $controls;
private $name;

function __construct() {
$this->controls = array();
}

function addControl($obj) {
$this->controls[$obj->getName()] = $obj;
}

function setName($value) { $this->name = $value; }
function getName() { return $this->name; }

// эта функция из IteratorAggregate
function getIterator() {
return $this->controls;
}
}

$c1 = new Control();
$c1->setName('userId');
$c2 = new Control();
$c2->setName('userName');
$form = new Control();
$form->addControl($c1);
$form->addControl($c2);

foreach ($form as $ctrl) {
echo $ctrl->getName() . '
';
}

Этот вариант является только надстройкой над стандартной функциональностью PHP и может использоваться когда до начала итерации можно получить все элементы, участвующие в итрации. Если же этого сделать нельзя (в случае получения записей из базы данных или чтении строк из большого файла), используется другой механизм расширения итерации - реализация интерфейса Iterator.

interface Iterator {
function rewind(); // переводит итерацию к первому элементу
function next(); // подготавливает к выводу следующий элемент
function key(); // возвращает ключ текущего элемента
function current(); // возвращает текущий элемент
function hasMore(); // возвращает true, если есть еще элементы, иначе false
}

Следующий пример показывает итерацию до нахождения нужного элемента:

class Control {
private $name;

function setName($value) { $this->name = $value; }
function getName() { return $this->name; }
}

class Controls implements Iterator {
private $controls;
private $controlNames;
private $num;

function __construct() {
$this->controls = array();
}

function addControl($obj) {
$this->controls[$obj->getName()] = $obj;
}

// функция использует возможности итерации класса для
// поиска контрола с заданным именем
function findControl($name) {
foreach ($this as $control) {
if ($control->getName() == $name)
return $control;
}

return null;
}

// следующие функции из Iterator
function rewind() {
$this->controlNames = array_keys($controls);
$this->num = 0;
}

function next() {
$this->num++;
}

function key() {
return $this->controlNames($this->num);
}

function current() {
return $this->controls[$this->key()];
}

function hasMore() {
return $this->num < count($this->controlNames);
}

}

$c1 = new Control();
$c1->setName('userId');
$c2 = new Control();
$c2->setName('userName');
$formControls = new Controls();
$formControls->addControl($c1);
$formControls->addControl($c2);

$userId = $formControls->findControl('userId');
$userName = $formControls->findControl('userName');

Константа __METHOD__

Константа __METHOD__ является хорошим дополнением к уже существующим "магическим" константам PHP4: __LINE__, __FILE__, __FUNCTION__ (с PHP4.3.0), __CLASS__ (с PHP4.3.0). Такие константы названны магическими, поскольку они меняют свое значение в зависимости от места вызова. Думаю, что вполне очевидно, что они возвращают, за исключением разницы между __FUNCTION__ и __METHOD__, поскольку функция класса и является его методом. Судя по всему, разработчики PHP5 решили, что константы __FUNCTION__, возвращающий только имя функции или метода класса, будет недостаточно и добавили константу __METHOD__, возврающую имя класса (в нижнем регистре) и имя метода, разделенные двумя двоеточиями.

Таким образом, следующий код выведет текст "myclass|myMethod|myclass::myMethod":

Class MyClass {
function myMethod() {
echo __CLASS__ . '|' . __FUNCTION__ . '|' . __METHOD__;
}
}

$m = new MyClass();
$m->myMethod();

Метод __toString()

Когда переменная-объект преобразуется к строке, в результате возвращается строка "Object id #n", где n - номер объекта в глобальной таблице объектов. Если понадобится (пусть и крайне редко), этот механизм можно изменить, создав у класса метод __toString(), возвращающий некоторое строковое представление текущего объекта.

Хотя PHP5 beta 3 этот алгоримт проработан не полностью (__toString() срабатывает только во время использования указателя на объект в операторе print), это открывает интересные перспективы. Например, следующий код представляет собой вариацию на тему типизации PHP:

class Integer {
private $value;
function __construct($val) {
$this->value = $val;
}
function __toString() {
return (string)($this->value);
}
}

$i = new Integer(10);
/**
Теоритически, $i при преобразовании к строке должно дать "10", и, поскольку число 10 сравнивается со строкой, оно тоже должно быть приведенно к строке. Получится "10" == "10". На практике, в этом случае преобразование $i к строке осуществляется по варианту PHP (т.е. в результате получаем строку "Object").
*/

if (10 == $i)
echo '10!!!! :-)';

Reflection API

Reflection не является новым понятием для PHP, но только в PHP5 предпринята попытка привести работу со структурными объектами языка к общему виду. Под структурными объектами понимаются функции, классы, интерфейсы, параметры и расширения.

Классы Reflection позволяют получать информацию о объектах языка непосредственно во время выполнения скрипта. Например, можно получить информацию о некотором объекте, включая его методы, их параметры, в каком файле находится описание объекта и даже какой документационный комментарий находится перед ним.

Reflection классы сделанны для каждого структурного объекта языка:

  • Reflection_Function
  • Reflection_Parameter
  • Reflection_Method
  • Reflection_Class
  • Reflection_Property
  • Reflection_Extension

В отличии от большинства других изменений в PHP5, Reflections уже неплохо документированны. Подробное описание доступно по адресу http://sitten-polizei.de/php/reflection_api/docs/language.reflection.html.

Пример использования Reflection:

/**
MyClass просто пример класса для демонстрации Reflection.
Этот код будет выведен как документация к классу MyClass при Reflection.
*/
class MyClass {

/**
А это комментарий к конструктору
*/
function __construct() {
}
}

Reflection::export(new Reflection_Class('MyClass'));

Результатом работы этого кода будет следующее описание класса:

/**
MyClass просто пример класса для демонстрации Reflection.
Этот код будет выведен как документация к классу MyClass при Reflection.
*/
Class [ class myclass ] {
@@ /articles/docs/test.php 7-14

- Constants {
}

- Static properties {
}

- Static methods {
}

- Properties {
}

- Methods {
/**
А это комментарий к конструктору
*/
Method [ public method __construct ] {
@@ /articles/docs/test.php 12 - 13
}
}
}

Вау!! 😲 Ты еще не читал? Это зря!

На этом все! Теперь вы знаете все про объектно-ориентированное программирование, Помните, что это теперь будет проще использовать на практике. Надеюсь, что теперь ты понял что такое объектно-ориентированное программирование, ооп в php, интерфейсы, классы, абстрактные классы, объекты и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)

Продолжение:


Часть 1 Объектно-ориентированное программирование (ООП) в PHP Интерфейсы, классы, абстрактные классы, объекты
Часть 2 Вау!! 😲 Ты еще не читал? Это зря! - Объектно-ориентированное программирование (ООП) в PHP Интерфейсы, классы,

создано: 2014-10-16
обновлено: 2024-11-14
353



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей

Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)

Термины: Выполнение скриптов на стороне сервера PHP (LAMP) NodeJS (Backend)