1. Введение
Реализация обязательных типов объектов в PHP иногда может быть очень важной. Если он отсутствует либо из-за недостатка знаний (из-за неверных предположений о программировании), либо просто из-за лени, то вы увидите в своем конкретном веб-приложении результаты, которых не ожидаете. Особенно при программировании на PHP 4 очень легко использовать функцию «is_a()» (хотя существуют и другие методы), чтобы проверить тип объекта, с которым вы работаете. Конечно, принудительные типы объектов также можно использовать для фильтрации входных объектов, которые необходимо передавать в качестве параметров другим классам PHP в том же приложении.
Однако PHP 4 не выявил некоторых недостатков своей объектной модели — иногда может потребоваться написание дополнительного кода для реализации определенных функций, имеющихся в зрелых объектно-ориентированных языках. Этот факт давно известен PHP-сообществу. Однако с выпуском PHP 5 многие из этих чрезвычайно ценных функций были добавлены как часть улучшенной объектной модели. Они помогут более точно реализовать разработку объектно-ориентированного кода, позволяя использовать конкретные характеристики объекта.
В приведенном выше случае следует проявлять особую осторожность, когда речь идет о приведении типов объектов. Фактически, PHP 5 предоставляет разработчикам как минимум два способа проверки типов объектов во время выполнения веб-приложения — это оператор «instanceof» и функция «подсказки типа». Теперь, переходя к основной теме этой статьи, я расскажу об использовании оператора «instanceof» в PHP 5. Вскоре вы обнаружите, что он может быть очень удобен для определения принадлежности объекта, с которым вы работаете, к определенному типу;
Эта статья поможет вам понять, как реализовать обязательные типы объектов в PHP 5, на некоторых объектно-ориентированных примерах.
2. Чего не следует делать
Чтобы показать, как реализовать приведение типов объектов в PHP 5, я буду использовать класс виджета (X)HTML и простой класс построителя страниц с простыми изменениями, подходящими для среды разработки PHP 5.
В моем первом примере перечислены некоторые классы виджетов (X)HTML, производные от абстрактного базового класса «HTMLElement», который пропускает проверку типа входных объектов. Сначала посмотрите на следующий класс:
//Определите абстрактный класс «HTMLElement»
абстрактный класс HTMLElement{
защищенные $attributes;
защищенная функция __construct($attributes){
if(!is_array($attributes)){
throw new Exception('Неверный тип атрибута');
}
$this->attributes=$attributes;
}
// Абстрактный метод 'getHTML()' абстрактная защищенная функция getHTML();
}
//Определение конкретного класса 'Div' - расширяет HTMLElement
класс Div расширяет HTMLElement{
частный $output='<div ';
частные $данные;
общественная функция __construct($attributes=array(),$data){
родитель::__construct($атрибуты);
$this->data=$data;
}
//Конкретная реализация метода getHTML() public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</div>';
вернуть $this->вывод;
}
}
//Определяем конкретный класс «Header1» — расширяет HTMLElement
класс Header1 расширяет HTMLElement{
частный $output='<h1 ';
частные $данные;
общественная функция __construct($attributes=array(),$data){
родитель::__construct($атрибуты);
$this->data=$data;
}
//Конкретная реализация метода getHTML() public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</h1>';
вернуть $this->вывод;
}
}
//Определяем конкретный класс «Абзац» — расширяет HTMLElement
Класс Paragraph расширяет HTMLElement{
частный $output='<p ';
частные $данные;
общественная функция __construct($attributes=array(),$data){
родитель::__construct($атрибуты);
$this->data=$data;
}
//Конкретная реализация метода getHTML() public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</p>';
вернуть $this->вывод;
}
}
//Определяем конкретный класс UnorderedList — расширяет HTMLElement
класс UnorderedList расширяет HTMLElement{
частный $output='<ul ';
частный $items=массив();
общественная функция __construct($attributes=array(), $items=array()){
родитель::__construct($атрибуты);
если(!is_array($items)){
throw new Exception('Неверный параметр для элементов списка');
}
$this->items=$items;
}
//Конкретная реализация метода getHTML() public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
foreach($this->items as $item){
$this->output.='<li>'.$item.'</li>';
}
$this->output.='</ul>';
вернуть $this->вывод;
}
}
Как видите, приведенные выше классы виджетов (X)HTML очень полезны для создания определенных элементов в сети, но я намеренно написал код для каждого класса, чтобы они не могли проверять эффективность входных параметров. Как вы могли догадаться, входные параметры передаются непосредственно в конструктор класса и назначаются как свойства. Возникает вопрос: а есть ли в этом что-то плохое? Да, есть. Теперь я собираюсь определить свой простейший класс построителя страниц и снабдить его такими виджетами, чтобы вы могли видеть, как входные данные этого класса смешиваются с неправильными объектами. Вот сигнатура класса генератора страниц:
class PageGenerator{
частный $output='';
частный $title;
публичная функция __construct($title='Страница по умолчанию'){
$this->title=$title;
}
публичная функция doHeader(){
$this->output='<html><head><title>'.$this-
>title.'</title></head><body>';
}
общественная функция addHTMLElement($htmlElement){
$this->output.=$htmlElement->getHTML();
}
публичная функция doFooter(){
$this->output.='</body></html>';
}
публичная функция fetchHTML(){
вернуть $this->вывод;
}
}
Теперь мы начинаем создавать экземпляры некоторых (X)HTML-виджетов и передавать их соответствующим классам-генераторам, как показано в следующем примере:
try{
//Создаем несколько элементов HTML $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'Содержимое для H1
элемент идет сюда');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Содержимое для элемента Div
идет сюда');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Содержимое абзаца
элемент идет сюда');
$ul=new UnorderedList(array ('name'=>'list1', 'class'=>'listclass'), массив
('item1'=>'value1', 'item2'=>'value2', 'item3'=>'value3'));
//Создаем экземпляр класса генератора страниц $pageGen=new Page Generator();
$pageGen->doHeader();
//Добавляем объект HTMLElement $pageGen->addHTMLElement($h1);
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->addHTMLElement($ul);
$pageGen->doFooter();
//Отображение веб-страницы echo $pageGen->fetchHTML();
}
catch(Исключение $e){
echo $e->getMessage();
Выход();
}
После запуска приведенного выше PHP-кода вы получите простую веб-страницу, содержащую некоторые (X)HTML-объекты, созданные ранее. В этом случае легко понять, что произойдет, если по какой-то причине класс компоновщика страниц получит неправильный объект и вызовет его метод «addHTML()». Здесь я переработал условие конфликта — используя несуществующий объект виджета (X)HTML. Пожалуйста, просмотрите следующий код еще раз:
try{
//Создаем несколько элементов HTML $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'Содержимое для H1
элемент идет сюда');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Содержимое для элемента Div
идет сюда');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Содержимое абзаца
элемент идет сюда');
$ul=new UnorderedList(array ('name'=>'list1', 'class'=>'listclass'), массив
('item1'=>'value1', 'item2'=>'value2', 'item3'=>'value3'));
//Создаем экземпляр класса генератора страниц $pageGen=new Page Generator();
$pageGen->doHeader();
//Добавляем объект HTMLElement $pageGen->addHTMLElement($fakeobj) //Передаем несуществующий объект в этот метод $pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->addHTMLElement($ul);
$pageGen->doFooter();
// Отображение эха страницы $pageGen->fetchHTML();
}
catch(Исключение $e){
echo $e->getMessage();
Выход();
}
В этом случае, как показано в следующей строке:
$pageGen->addHTMLElement($fakeobj)//Передача несуществующего объекта этому методу.
Несуществующий объект виджета (X)HTML передается классу генератора страниц, это приведет к фатальной ошибке:
Неустранимая ошибка: вызов функции-члена для объекта, не являющегося объектом в
А как насчет
пути/к/файлу
?Это прямое наказание за непроверку типа объекта, передаваемого в класс-генератор! Поэтому обязательно имейте это в виду при написании сценариев. К счастью, есть простое решение этих проблем, и именно здесь на помощь приходит оператор «instanceof». Если вы хотите увидеть, как используется этот оператор, читайте дальше.
3. Используйте оператор «instanceof».
Как видите, использовать оператор «instanceof» очень просто. Для выполнения своей функции он использует два параметра. Первый параметр — это объект, который вы хотите проверить, а второй параметр — это имя класса (фактически имя интерфейса), используемое для определения того, является ли объект экземпляром соответствующего класса. Конечно, я намеренно использовал приведенную выше терминологию, чтобы вы могли увидеть, насколько интуитивно понятно использование этого оператора. Его основной синтаксис следующий:
if (имя класса экземпляра объекта){
//Сделаем что-нибудь полезное
}
Теперь, когда вы понимаете, как этот оператор используется в PHP 5, давайте определим соответствующий класс построителя веб-страниц, чтобы проверить тип объекта, передаваемого в его метод «addHTMLElement()». Вот новая сигнатура этого класса, который, как я упоминал ранее, использует оператор «instanceof»:
class PageGenerator{
частный $output='';
частный $title;
публичная функция __construct($title='Страница по умолчанию'){
$this->title=$title;
}
публичная функция doHeader(){
$this->output='<html><head><title>'.$this->title.'</title></head><body>';
}
общественная функция addHTMLElement($htmlElement){
if(!$htmlElement экземпляр HTMLElement){
throw new Exception('Неверный (X)HTML-элемент');
}
$this->output.=$htmlElement->getHTML();
}
публичная функция doFooter(){
$this->output.='</body></html>';
}
публичная функция fetchHTML(){
вернуть $this->вывод;
}
}
Обратите внимание: в приведенном выше классе оператор «instanceof» включен в метод «addHTMLElement()», чтобы гарантировать, что все передаваемые объекты являются экземплярами класса «HTMLElement», определенного ранее. Теперь можно восстановить веб-страницу, которую вы видели ранее, и в этом случае убедитесь, что все входные объекты, переданные в класс компоновщика веб-страниц, являются реальными объектами виджетов (X)HTML. Вот соответствующий пример:
try{
//Создаем несколько элементов HTML $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'Здесь находится содержимое элемента H1');
$div=new Div(array('name'=>'div1', 'class'=>'divclass'), 'Здесь находится содержимое элемента Div');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Здесь находится содержимое элемента Paragraph');
$teststr='Это не элемент HTML';
//Создаем экземпляр класса генератора страниц $pageGen=new Page Generator();
$pageGen->doHeader();
//Добавляем объект HTMLElement $pageGen->addHTMLElement($teststr) //Передаем в этот метод простую строку $pageGen->addHTMLElement($h1);
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->doFooter();
//Отображение веб-страницы echo $pageGen->fetchHTML();
}
catch(Исключение $e){
echo $e->getMessage();
Выход();
}
Как вы видели в приведенном выше примере, я передаю простую тестовую строку (а не объект «HTMLElement») в класс компоновщика страниц, который выдаст исключение, перехваченное определенным блоком «catch», как показано ниже:
Неверный элемент (X)HTML.
В этот раз, чтобы определить достоверность входного объекта, я использовал оператор «instanceof», чтобы приведенная выше веб-страница могла быть видна. Надеюсь, вы действительно понимаете важность фильтрации входных данных для методы вашего класса, чтобы избежать посторонних ошибок с помощью этого оператора. Ввод данных.
После демонстрации правильной реализации оператора «instanceof» внутри класса генератора веб-страниц можно сделать больше, аналогично тому, что я написал для PHP 4 в предыдущей статье. (X). Для классов виджетов HTML я хотел бы включить этот оператор как часть метода getHTML(), что позволит создавать веб-страницы, генерирующие вложенные элементы (X)HTML. Давайте обсудим, как это достигается.
4. Расширьте использование оператора «instanceof». Вложенные (X)HTML-виджеты
хороши. Вы видели, что оператор «instanceof» хорошо справляется с проверкой типов входных объектов, которые непосредственно внедряются в функциональность класса компоновщика страниц. Теперь я пойду еще дальше и добавлю процедуру проверки в конструктор и метод getHTML() класса виджетов (X)HTML, чтобы они могли принимать другие виджеты в качестве входных параметров. Проверьте улучшения, приведенные ниже.
класс Div расширяет HTMLElement{
частный $output='<div ';
частные $данные;
общественная функция __construct($attributes=array(),$data){
if(!$data экземпляр HTMLElement&&!is_string($data)){
выдать новое исключение («Неверный тип параметра»);
}
родитель::__construct($атрибуты);
$this->data=$data;
}
//Конкретная реализация метода getHTML() public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=($this->экземпляр данных HTMLElement)?
$this->data->getHTML():$this->data;
$this->output.='</div>';
вернуть $this->вывод;
}
}
класс Header1 расширяет HTMLElement{
частный $output='<h1 ';
частные $данные;
общественная функция __construct($attributes=array(),$data){
if(!$data экземпляр HTMLElement&&!is_string($data)){
выдать новое исключение («Неверный тип параметра»);
}
родитель::__construct($атрибуты);
$this->data=$data;
}
//Конкретная реализация метода getHTML() public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=($this->экземпляр данных HTMLElement)?
$this->data->getHTML():$this->data;
$this->output.='</h1>';
вернуть $this->вывод;
}
}
Класс Paragraph расширяет HTMLElement{
частный $output='<p ';
частные $данные;
общественная функция __construct($attributes=array(),$data){
if(!$data экземпляр HTMLElement&&!is_string($data)){
выдать новое исключение («Неверный тип параметра»);
}
родитель::__construct($атрибуты);
$this->data=$data;
}
//Конкретная реализация метода getHTML() public function getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=($this->экземпляр данных HTMLElement)?
$this->data->getHTML():$this->data;
$this->output.='</p>';
вернуть $this->вывод;
}
}
класс UnorderedList расширяет HTMLElement{
частный $output='<ul ';
частный $items=массив();
общественная функция __construct($attributes=array(), $items=array()){
родитель::__construct($атрибуты);
если(!is_array($items)){
throw new Exception('Неверный параметр для элементов списка');
}
$this->items=$items;
}
//Конкретная реализация метода getHTML()
публичная функция getHTML(){
foreach($this->attributes as $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
foreach($this->items as $item){
$this->output.=($item экземпляр
HTMLElement)?'<li>'.$item->getHTML().'</li>':'<li>'.$item.'</li>';
}
$this->output.='</ul>';
вернуть $this->вывод;
}
}
Как показано в приведенных выше классах, чтобы разрешить реализацию вложенных (X)HTML-элементов при создании соответствующих веб-страниц, я провел рефакторинг их конструкторов и методов getHTML() соответственно. Обратите внимание, что я включил в конструктор каждого класса следующий условный блок:
if(!$data instanceof HTMLElement&&!is_string($data)){
выдать новое исключение («Неверный тип параметра»);
}
На данный момент я на самом деле проверяю, что в качестве входных параметров для каждого класса разрешены только строковые данные и объекты типа «HTMLElement». В противном случае соответствующим методом будет выброшено исключение, что может привести к остановке выполнения приложения. Итак, это процесс проверки входных данных. Теперь давайте посмотрим на новую сигнатуру метода getHTML(), которая также использует оператор indexof:
$this->output.=($this->data instanceof HTMLElement)?$this->data-
>getHTML():$this->data;
Как видите, в данном случае оператор this очень полезен для использования полиморфных возможностей класса виджета (X)HTML. Если атрибут $data также является виджетом, то его метод getHTML() будет вызван правильно, что приведет к отображению вложенного веб-элемента. С другой стороны, если это просто строка, то она добавляется непосредственно ко всем выводам текущего класса.
К этому моменту вы, возможно, поняли, как используется оператор «instanceof» в PHP 5, чтобы гарантировать принадлежность определенных объектов к определенному типу. Как вы можете видеть из этой статьи, приведение типов объектов в PHP 5 на самом деле является довольно простой задачей. А пока вам лучше разработать пример использования этого метода для фильтрации объектов в вашем приложении PHP, чтобы углубить ваше понимание.
5. Резюме
В этой статье вы узнали, как использовать оператор «instanceof» в PHP 5 для проверки типа вашего объекта ввода, однако метод, который я вам показал, не единственный; В следующей статье я объясню вам, как реализовать в PHP 5 удобную функцию «подсказки типа», которая является еще одним способом обеспечить типизацию объектов.
Автор: Чжу Сяньчжун. Составитель. Источник: Tianji Development.