Основы PHP
  Что такое PHP?
  Возможности PHP
  Преимущества PHP
  История развития
  Что нового в PHP5?
  «Движок» PHP
  Переход на PHP 5.3
New Переход на PHP 5.6
  Введение в PHP
  Изучение PHP
  Основы CGI
  Синтаксис PHP
  Типы данных PHP
  Переменные в PHP
  Константы PHP
  Выражения PHP
  Операторы PHP
  Конструкции PHP
  Ссылки в PHP
  PHP и ООП
  Безопасность
  Функции PHP
  Функции по категориям
  Функции по алфавиту
  Стандартные функции
  Пользовательские
  PHP и HTTP
  Работа с формами
  PHP и Upload
  PHP и Cookies
  PHP и базы данных
  PHP и MySQL
  Документация MySQL
  Учебники
  Учебники по PHP
  Учебники по MySQL
  Другие учебники
  Уроки PHP
  Введение
  Самые основы
  Управление
  Функции
  Документация
  Математика
  Файлы
  Основы SQL
  Дата и время
  CURL
  Изображения
  Стили
  Безопасность
  Установка
  Проектирование БД
  Регулярные выражения
  Подготовка к работе
  Быстрый старт
  Установка PHP
  Установка MySQL
  Конфигурация PHP
  Download / Скачать
  Скачать Apache
  Скачать PHP
  Скачать PECL
  Скачать PEAR
  Скачать MySQL
  Редакторы PHP
  Полезные утилиты
  Документация
  PHP скрипты
  Скачать скрипты
  Инструменты
  PHP в примерах
  Новости портала
 Главная   »  Сборник статей
 
 

Новая объектная модель

Автор: Данил Миронов

В целях внедрения новых возможностей и для увеличения скорости работы система управления объектами в Zend Engine была полностью изменена.

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

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

Закрытые члены

В Zend Engine 2.0 вводятся закрытые свойства. Отметим, что при несанкционированном доступе к закрытому атрибуту сообщение об ошибке не выводится: во избежание замедления работы.

Пример 1: Закрытые члены

<?php
class MyClass {
    private
$Hello = "Hello, World!\n";

    function
printHello() {
        print
$this->Hello;
    }
}

class
MyClass2 extends MyClass {
    function
printHello() {
        
MyClass::printHello(); /* Есть вывод */
        
print $this->Hello;    /* Нет вывода */
    
}
}

$obj = new MyClass();
print
$obj->Hello;  /* Нет вывода */
$obj->printHello(); /* Есть вывод */

$obj = new MyClass2();
print
$obj->Hello;  /* Нет вывода */
$obj->printHello();
?&
gt;

Клонирование объектов

В Zend Engine 1.0 при копировании объектов пользователь не мог решать, что конструктор должен копировать, а что нет. Версия 1.0 производила побитное копирование объекта и давала на выходе полную копию всех его свойств.

Однако абсолютное копирование объекта с полным набором свойств - это не всегда то, что нам нужно. Хороший тому пример - у вас есть объект, представляющий собой окно GTK и информация обо всех элементах интерфейса этого окна также хранится в объекте. Вам может понадобиться создать новое окно (копию первого) и хранить данные по всем элементам интерфейса нового окна в новом объекте. Другой вариант - в вашем объекте содержится ссылка на другой объект, который как-либо им используется. Клонируя ваш родительский объект, вы тем самым создаёте копию другого объекта и таким образом, у дубликата вашего объекта есть своя копия того используемого объекта.

Копия объекта создаётся методом __clone() этого объекта.

Когда разработчик вызывает создание клона какого-либо объекта, Zend Engine проверяет, был ли определён метод __clone(). Если метод не был определён, то вызывается __clone() по умолчанию, и все свойства объекта дуплицируются полностью. Если же метод был определён, то именно он перечисляет свойства объекта, которые будут перенесены в его копию. Для удобства использования Zend Engine предоставит функцию, которая импортирует все свойства копируемого объект: таким образом, они будут в копии по значению, а разработчику останется лишь переписать свойства, которые нам нужно изменить [В данной версии эта функция ещё не реализована].

Пример 2: Клонирование объектов

<?php
class MyCloneable {
    static
$id = 0;

    function
MyCloneable() {
        
$this->id = self::$id++;
    }

    function
__clone() {
        
$this->name = $clone->name;
        
$this->address = 'New York';
        
$this->id = self::$id++;
    }
}

$obj = new MyCloneable();

$obj->name    = 'Hello';
$obj->address = 'Tel-Aviv';

print
$obj->id . "\n";

$obj = $obj->__clone();

print
$obj->id . "\n";
print
$obj->name . "\n";
print
$obj->address . "\n";
?&
gt;

Принудительное уничтожение объектов

Zend Engine 1.0 не содержала средств принудительного уничтожения объекта, если ссылки на него ещё существовали. Оператор delete, введённый в новой версии, вызывает деструктор объекта и освобождает занимаемую объектом память, даже если в других местах системы содержатся ссылки на него. Все ссылки на уничтоженный объект становятся устаревшими, и попытки получить доступ через них приводят к появлению ошибки (fatal error).

Стоит иметь в виду, что если в вашем старом скрипте содержится определённая пользователем функция delete(), то в Zend Engine 2.0 такой скрипт выдаст вам ошибку синтаксиса (parse error), поскольку 'delete' является отныне зарезервированным словом.

Вложенные классы (пространство имён)

В Zend Engine 1.0 существовало только три области действия: глобальная, область действия-класс и область действия-функция. Все области кроме класса могли содержать переменные; только область-класс и глобальная область могли содержать функции и только глобалльная область могла содержать константы и классы. Это означает, что во всех версиях Zend Engine 1.0 метода обзора были ограничены во избежание конфликтов пространства имён.

В Zend Engine 2.0 вводится концепция вложенных классов для решения проблемы именных коллизий альтернативным методом: появляется возможность определить несколько таблиц имён, содержащих любые типы символов. Zend Engine всегда следит, в области какого класса находится выполнение, выставляя по умолчанию глобальную область. Каждый класс может содержать свой набор констант, функций и статических переменных. Для доступа к идентификаторам внутри класса используется оператор доступа к классу self::, например, возможна такая строка: self::$my_static_name = "Hello". С функциями, равно как и с константами, если вы не определили класс, которому они принадлежат, то сначала поиск будет произведён внутри текущего класса, затем, если поиск не принёс результата, будет исследована глобальная область действия. Если вам нужно произвести поиск только в глобальной области действия, вы можете задать это эксплицитно, через оператор доступа main::. Например, используя, main::strlen(), вы уверены, что вы вызываете именно strlen() из глобальной области действия. Таким образом, использовать main:: вам придётся лишь в случаях, когда вы создаёте метод, имеющий одинаковое имя с глобальной функцией. Синтаксис для доступа к константам тот же: self::MY_CONSTANT или main::MY_CONSTANT.

Иногда вам может не понравиться получать доступ к константам, переменным и классам через операторы доступа (например, MyClass::): вам приходится прибегать к ним слишком уж часто, а скорость набора у вас страдает. В таком случае вы можете импортировать функции, классы и константы из других классов через ключевое слово import. Название говорит само за себя, также ниже приведено несколько примеров.

Классы могут включать в себя классы

Пример 3: Вложенные классы

<?php
class DB::MySQL {
var
$host = '';

    function
db_connect($user) {
        print
"Connecting to MySQL database '$this->host' as $user\n";
    }
}

class
DB::Oracle {
    var
$host = 'localhost';

    function
db_connect($user) {
        print
"Connecting to Oracle database '$this->host' as $user\n";
    }
}

$MySQL_obj = new DB::MySQL();
$MySQL_obj->db_connect('Susan');

$Oracle_obj = new DB::Oracle();
$Oracle_obj->db_connect('Barbara');
?&
gt;


Классы могут cодержать константы

Пример 4: константы

<?php
class foo {
    const
hey = 'hello';
}

print
foo::hey;
?&
gt;

Поиск функций и констант проводится сначала в таблице имён текущего класса.

Пример 5: таблица имён класса

<?php
define
('foo', 'bar');

class
FooClass {
    const
foo = 'foobar';

    function
printFoo() {
        print
foo;
    }
}
?&
gt;

Код, приведённый ниже, выводит не "foo", а "foobar", поскольку константа класса переписывает одноимённую константу глобальной области.

Внутри области действия функции используется таблица имён класса/пространства имён её содержащего.

Пример 6: таблица имён класса

<?php
class FooClass {
    function
foo() {
        
$this->bar();
        
bar();
    }

    function
bar() {
        print
"foobar\n";
    }
}

$obj = new FooClass;
$obj->foo();
$obj->foo();
?&
gt;

"foobar" выводится дважды, поскольку метод bar() уже существует в данном пространстве имён.

Существует созможность "импортировать" имена из одного пространства в другое:

Пример 7: импорт имён

<?php
class MyClass {
    class
MyClass2 {
        function
hello() {
            print
"Hello, World in MyClass2\n";
        }
    }

    function
hello() {
        print
"Hello, World\n";
    }
}

import function hello, class MyClass2 from MyClass;

MyClass2::hello();
hello();
?&
gt;

Пример 8: импорт имён

<?php
class MyOuterClass {
    class
MyInnerClass {
        function
func1() {
            print
"func1()\n";
        }

        function
func2() {
            print
"func2()\n";
        }
    }
}

import class * from MyOuterClass;
import function func2 from MyOuterClass::MyInnerClass;

MyInnerClass::func1();
func2();
?&
gt;

Пример 9: импорт имён

<?php
class MyOuterClass {
    const
Hello = "Hello, World\n";
}

import const Hello from MyOuterClass;
print
Hello;
?&
gt;

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

Унифицированные конструкторы

Zend Engine позволяет разработчиком определять для классов свои методы-конструкторы. Классы, где конструктор определён, вызывают этот метод при создании каждого нового экземпляра, то есть, проводится вся инициализация, необходимая для использования этого объекта.

В Zend Engine 1.0, методы-конструкторы представляли собой методы класса одноимённые с ним. Из-за широко распространённой практики вызывать конструктор родительского класса из производных классов, такая особенность Zend Engine 1.0 превращала перемещение от одного класса (при сложной иерархии классов) к другому в громоздкую и медленную работу. И если какой-либо производный класс будет перемещён к другому родителю, то имя конструктора родительского класса, само собой, изменится, и код вызова этого конструктора из производного класса придётся менять.

В Zend Engine 2.0 вводится новый унифицированный способ объявления метода-конструктора: называть конструктор именем __construct().

Пример 10: Унифицированные конструкторы

<?php
class BaseClass {
    function
__construct() {
        print
"In BaseClass constructor\n";
    }
}

class
SubClass extends BaseClass {
    function
__construct() {
        
parent::__construct();
        print
"In SubClass constructor\n";
    }
}

$obj = new BaseClass();
$obj = new SubClass();
?&
gt;

Для сохранения совместимости с предыдущими версиями, если Zend Engine 2.0 не найдёт метода с именем __construct() для данного класса, будет произведён поиск конструктора, объявленного по старым правилам, то есть одноимённого с классом. Проблема совместимости со скриптами предыдущих версий может возникнуть только в одном случае: если ваш класс содержит метод __construct(), используемый для других целей.

Унифицированные деструкторы

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

В Zend Engine 1.0 не было никаких средств поддержки деструкторов, хотя PHP уже поддерживал функции ведения лога, которые вызывались при остановке запроса.

В Zend Engine 2.0 вводится концепция деструктора, схожая с деструкторами в объектно-ориентированными языками, например, в Java: когда уничтожается последняя ссылка на объект, перед освобождением занимаемой им памяти вызывается деструктор. Последний представляет собой метод класса с именем __destruct() и не принимающий параметров.

Пример 11: Унифицированные деструкторы

<?php
class MyDestructableClass {
    function
__construct() {
        print
"In constructor\n";
        
$this->name = 'MyDestructableClass';
    }

    function
__destruct() {
        print
'Destroying ' . $this->name . "\n";
    }
}

$obj = new MyDestructableClass();
?&
gt;

Как и конструкторы, деструктор родителя автоматически не вызывается. Для этой операции вам необходимо явно вызвать parent::__destruct() в теле деструктора.

Исключения

В Zend Engine 1.0 управление исключениями не поддерживалось. В Zend Engine 2.0 вводится модель исключений сходная с подобными моделями в других языках.

Пример 12: Исключения

<?php
class MyException {
    function
__construct($exception) {
        
$this->exception = $exception;
    }

    function
Display() {
        print
"MyException: $this->exception\n";
    }
}

class
MyExceptionFoo extends MyException {
    function
__construct($exception) {
        
$this->exception = $exception;
    }

    function
Display() {
        print
"MyException: $this->exception\n";
    }
}

try {
    throw new
MyExceptionFoo('Hello');
}

catch (
MyException $exception) {
    
$exception->Display();
}
?&
gt;

Скипты предыдущих версий без определённых пользователем функций 'catch', 'throw', 'try' будут работать без изменений.

Разыменовывание объектов, полученных из функций.

Пример 13: Разыменовывание объектов

<?php
class Circle {
    function
draw() {
        print
"Circle\n";
    }
}

class
Square {
    function
draw() {
        print
"Square\n";
    }
}

function
ShapeFactoryMethod($shape) {
    switch (
$shape) {
        case
'Circle': return new Circle();
        case
'Square': return new Square();
    }
}

ShapeFactoryMethod('Circle')->draw();
ShapeFactoryMethod('Square')->draw();
?&
gt;

Инициализация статических членов классов.

Пример 14: Инициализация статических членов

<?php
class foo {
    static
$my_static = 5;
}

print
foo::$my_static;
?&
gt;

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

Пример 15: Значения по умолчанию

<?php
function my_function(&$var = null) {
    if (
$var === null) {
        die(
'$var needs to have a value');
    }
}
?&
gt;


Встроенная обратная трассировка.

Пример 16: Значения Обратная трассировка

<?php
$backtrace
= debug_backtrace();

foreach (
$backtrace as $step) {
    
$class = isset($step['class']) ? $step['class'] . '::' : '';

    
printf(
        
"%s [%s:%s]\n",
        
$step['function'],
        
$step['file'],
        
$step['line']
        );
}
?&
gt;

 
 » Обсудить эту статью на форуме

 
 Сборник статей 
 Содержание раздела 
Есть еще вопросы или что-то непонятно - добро пожаловать на наш  форум портала PHP.SU 
 

 
Powered by PHP  Powered By MySQL  Powered by Nginx  Valid CSS