1. はじめに
PHP で必須のオブジェクト型を実装することは、場合によっては非常に重要です。これが欠落している場合、知識不足 (間違ったプログラミングの前提に基づくもの) または単に怠惰が原因で、特定の Web アプリケーションで予期しない結果が表示されることになります。特に PHP 4 でプログラミングする場合、「is_a()」関数 (他のメソッドもありますが) を使用して、作業しているオブジェクトの型を確認するのが非常に簡単です。もちろん、オブジェクト型の強制を使用して、同じアプリケーション内の他の PHP クラスにパラメータとして渡す必要がある入力オブジェクトをフィルタリングすることもできます。
ただし、PHP 4 は、そのオブジェクト モデルに関するいくつかの弱点を明らかにしません。成熟したオブジェクト指向言語に見られる特定の機能を実装するために、追加のコードを記述する必要がある場合があります。この事実は PHP コミュニティでは長い間知られていました。ただし、PHP 5 のリリースでは、これらの非常に価値のある機能の多くが、改良されたオブジェクト モデルの一部として追加されました。これらは、オブジェクトベースのコード開発をより厳密に実装するのに役立ち、特定のオブジェクトの特性を使用できるようになります。
上記の場合、オブジェクト型の強制に関しては特別な注意が必要です。実際、PHP 5 は、Web アプリケーションの実行中にオブジェクトの型をチェックする少なくとも 2 つの方法を開発者に提供します。それらは、「instanceof」演算子と「型ヒント」機能です。ここでこの記事の本題に戻り、PHP 5 の「instanceof」演算子の使用法を紹介します。操作しているオブジェクトが特定の型に属しているかどうかを判断するのに非常に便利であることがすぐにわかります。
この記事は、いくつかのオブジェクト指向の例を通じて、PHP 5 で必須のオブジェクト型を実装する方法を理解するのに役立ちます。
2. してはいけないこと
PHP 5 でオブジェクト型強制を実装する方法を示すために、(X)HTML ウィジェット クラスと、PHP 5 開発環境に合わせて簡単な変更を加えた単純なページ ビルダー クラスを使用します。
最初の例では、入力オブジェクトの型のチェックをスキップする、抽象基本クラス「HTMLElement」から派生するいくつかの (X)HTML ウィジェット クラスをリストします。まず次のクラスを見てください:
//抽象クラス 'HTMLElement' を定義します。
抽象クラス HTMLElement{
保護された $attributes;
保護された関数 __construct($attributes){
if(!is_array($attributes)){
throw new Exception('無効な属性タイプ');
}
$this->attributes=$attributes;
}
// 抽象 'getHTML()' メソッド、抽象保護関数 getHTML();
}
// 特定のクラス 'Div' を定義します - HTMLElement を拡張します
class Div extends HTMLElement{
プライベート $output='<div ';
プライベート $data;
パブリック関数 __construct($attributes=array(),$data){
親::__construct($attributes);
$this->data=$data;
}
//「getHTML()」メソッドの具体的な実装 public function getHTML(){
foreach($this->属性として $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</div>';
$this->output を返します。
}
}
//具象クラス 'Header1' を定義 - HTMLElement を拡張します
class Header1 extends HTMLElement{
プライベート $output='<h1 ';
プライベート $data;
パブリック関数 __construct($attributes=array(),$data){
親::__construct($attributes);
$this->data=$data;
}
//「getHTML()」メソッドの具体的な実装 public function getHTML(){
foreach($this->属性として $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</h1>';
$this->output を返します。
}
}
//具体的なクラス 'Paragraph' を定義 - HTMLElement を拡張します
クラス パラグラフ extends HTMLElement{
プライベート $output='<p ';
プライベート $data;
パブリック関数 __construct($attributes=array(),$data){
親::__construct($attributes);
$this->data=$data;
}
//「getHTML()」メソッドの具体的な実装 public function getHTML(){
foreach($this->属性として $attribute=>$value){
$this->output.=$attribute.'="'.$value.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</p>';
$this->output を返します。
}
}
//具象クラス「UnownedList」を定義 - HTMLElement を拡張します
class UnownedList extends HTMLElement{
プライベート $output='<ul ';
プライベート $items=array();
パブリック関数 __construct($attributes=array(), $items=array()){
親::__construct($attributes);
if(!is_array($items)){
throw new Exception('リスト項目のパラメータが無効です');
}
$this->items=$items;
}
//「getHTML()」メソッドの具体的な実装 public function getHTML(){
foreach($this->属性として $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->output を返します。
}
ご覧のとおり、上記の (X)HTML ウィジェット クラスは Web で特定の要素を生成するのに非常に便利ですが、入力パラメーターの有効性を検証できないように、意図的に各クラスのコードを作成しました
。
ご想像のとおり、入力パラメーターはクラス コンストラクターに直接渡され、プロパティとして割り当てられます。これを行うことに何か問題があるのでしょうか?という疑問が生じます。はい、あります。ここで、最も単純なページ ビルダー クラスを定義し、このようなウィジェットをフィードして、このクラスへの入力がどのように不正なオブジェクトと混合されるかを確認します。ページ ジェネレーター クラスのシグネチャは次のとおりです。
class PageGenerator{
プライベート $output='';
プライベート $title;
パブリック関数 __construct($title='デフォルト ページ'){
$this->title=$title;
}
パブリック関数 doHeader(){
$this->output='<html><見出し><タイトル>'.$this-
>タイトル.'</タイトル></頭><本文>';
}
パブリック関数 addHTMLElement($htmlElement){
$this->output.=$htmlElement->getHTML();
}
パブリック関数 doFooter(){
$this->output.='</body></html>';
}
パブリック関数 fetchHTML(){
$this->output を返します。
}
ここ
、
いくつかの (X)HTML ウィジェット オブジェクトのインスタンス化を開始し、それらを対応するジェネレーター クラスに渡します。
//いくつかの HTML 要素を生成 $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'Content for H1
要素がここに入ります');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Div 要素の内容
ここに行きます');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'段落の内容
要素がここに入ります');
$ul=new UnownedList(array ('name'=>'list1', 'class'=>'listclass'), array
('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();
// Web ページを表示 echo $pageGen->fetchHTML();
}
catch(例外 $e){
echo $e->getMessage();
出口();
、
得られる結果は単純な Web ページです。これには、前に作成したいくつかの (X)HTML オブジェクトが含まれています。この場合、何らかの理由でページ ビルダー クラスが不正なオブジェクトを受け取り、その "addHTML()" メソッドを呼び出した場合に何が起こるかを理解するのは簡単です。ここでは、存在しない (X)HTML ウィジェット オブジェクトを使用して、競合状態を作り直しました。次のコードをもう一度見てください:
try{
//いくつかの HTML 要素を生成 $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'Content for H1
要素がここに入ります');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Div 要素の内容
ここに行きます');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'段落の内容
要素がここに入ります');
$ul=new UnownedList(array ('name'=>'list1', 'class'=>'listclass'), array
('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();
// ページを表示 echo $pageGen->fetchHTML();
}
catch(例外 $e){
echo $e->getMessage();
出口();
、
次の行に示すように:
$pageGen->addHTMLElement($fakeobj)//存在しないオブジェクトをこのメソッドに渡す
存在しない (X)HTML ウィジェット オブジェクトがページ ジェネレーター クラスに渡されます。致命的なエラーが発生します:
致命的なエラー: 非オブジェクトのメンバー関数の呼び出し
パス/ファイルへのパス
はどうなりますか
?これは、ジェネレーター クラスに渡されたオブジェクトの型をチェックしないことによる直接的なペナルティです。したがって、スクリプトを作成するときは、この点に必ず留意してください。幸いなことに、これらの問題には簡単な解決策があり、ここで「instanceof」演算子の力が役に立ちます。この演算子がどのように使用されるかを知りたい場合は、読み続けてください。
3. 「instanceof」演算子の使用
ご覧のとおり、「instanceof」演算子の使用は 2 つのパラメータを使用してその機能を完了します。最初のパラメータはチェックするオブジェクトで、2 番目のパラメータはオブジェクトが対応するクラスのインスタンスであるかどうかを判断するために使用されるクラス名 (実際にはインターフェイス名) です。もちろん、このオペレーターがいかに直感的に使用できるかを理解していただくために、上記の用語を意図的に使用しました。その基本的な構文は次のとおりです。
if (クラス名のオブジェクト インスタンス){
//何か役に立つことをする
、
「addHTMLElement()」メソッドに渡されるオブジェクトのタイプを確認するために、対応する Web ページ ビルダー クラスを定義しましょう。このクラスの新しいシグネチャは次のとおりです。先ほど説明したように、「instanceof」演算子が使用されています
。
プライベート $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->output を返します。
}
、
渡されるすべてのオブジェクトが以前に定義された「HTMLElement」クラスのインスタンスであることを保証するために、「instanceof」演算子が「addHTMLElement()」メソッドにどのように含まれているかに注意してください。これで、前に表示した Web ページを再構築できるようになります。その場合、Web ページ ビルダー クラスに渡されるすべての入力オブジェクトが実際の (X)HTML ウィジェット オブジェクトであることを確認してください。対応する例は次のとおりです
。
//いくつかの 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'),'段落要素のコンテンツがここに入ります');
$teststr='これは HTML 要素ではありません';
// ページ ジェネレーター クラスをインスタンス化します $pageGen=new Page Generator();
$pageGen->doHeader();
//「HTMLElement」オブジェクトを追加 $pageGen->addHTMLElement($teststr) //このメソッドに単純な文字列を渡します $pageGen->addHTMLElement($h1);
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->doFooter();
// Web ページを表示 echo $pageGen->fetchHTML();
}
catch(例外 $e){
echo $e->getMessage();
出口();
よう
に、単純なテスト文字列 (「HTMLElement」オブジェクトではない) をページ ビルダー クラスに渡します。これにより、以下に示すように、特定の「catch」ブロックによってキャッチされる例外がスローされます。
無効な (X)HTML 要素です
。このとき、入力オブジェクトの正当性を判断するために、「instanceof」演算子を使用しました。これにより、上記の Web ページは次のようになります。入力をフィルタリングすることの重要性を十分に理解していただければ幸いです。この演算子を使用して無関係なエラーを回避するクラスのメソッド。Web
ページ ジェネレーター クラス内の「instanceof」演算子の正しい実装を示した後、前の記事で PHP 4 について書いたことと同様の作業がさらにあります。 (X) HTML ウィジェット クラスの場合、この演算子を「getHTML()」メソッドの一部として含めて、ネストされた (X)HTML 要素を生成する Web ページを作成できるようにしたいと考えています。
4. 「instanceof」演算子の使用を拡張する: ネストされた (X)HTML ウィジェット
が優れています。「instanceof」演算子は、ページ ビルダー クラス機能に直接挿入される入力オブジェクトの型チェックで適切に機能することがわかりました。ここで、さらに一歩進んで、(X)HTML ウィジェット クラスのコンストラクターと「getHTML()」メソッドにチェック ルーチンを追加して、他のウィジェットを入力パラメーターとして受け入れられるようにします。以下の改善点を確認してください。
class Div extends HTMLElement{
プライベート $output='<div ';
プライベート $data;
パブリック関数 __construct($attributes=array(),$data){
if(!$data HTMLElement&&!is_string($data)){
throw new Exception('無効なパラメータの型');
}
親::__construct($attributes);
$this->data=$data;
}
//「getHTML()」メソッドの具体的な実装 public function getHTML(){
foreach($this->属性として $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->output を返します。
}
}
class Header1 extends HTMLElement{
プライベート $output='<h1 ';
プライベート $data;
パブリック関数 __construct($attributes=array(),$data){
if(!$data HTMLElement&&!is_string($data)){
throw new Exception('無効なパラメータの型');
}
親::__construct($attributes);
$this->data=$data;
}
//「getHTML()」メソッドの具体的な実装 public function getHTML(){
foreach($this->属性として $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->output を返します。
}
}
クラス パラグラフ extends HTMLElement{
プライベート $output='<p ';
プライベート $data;
パブリック関数 __construct($attributes=array(),$data){
if(!$data HTMLElement&&!is_string($data)){
throw new Exception('無効なパラメータの型');
}
親::__construct($attributes);
$this->data=$data;
}
//「getHTML()」メソッドの具体的な実装 public function getHTML(){
foreach($this->属性として $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->output を返します。
}
}
class UnownedList extends HTMLElement{
プライベート $output='<ul ';
プライベート $items=array();
パブリック関数 __construct($attributes=array(), $items=array()){
親::__construct($attributes);
if(!is_array($items)){
throw new Exception('リスト項目のパラメータが無効です');
}
$this->items=$items;
}
//「getHTML()」メソッドの具体的な実装
パブリック関数 getHTML(){
foreach($this->属性として $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->output を返します。
}
、
対応する Web ページを生成するときにネストされた (X)HTML 要素を実装できるようにするために、それらのコンストラクターと "getHTML()" メソッドをそれぞれリファクタリングしました。各クラスのコンストラクターに次の条件ブロックを含めたことに注意してください:
if(!$data instanceof HTMLElement&&!is_string($data)){
throw new Exception('無効なパラメータの型');
この
時点で、実際に行うことは、文字列データとタイプ「HTMLElement」のオブジェクトのみが各クラスの入力パラメーターとして許可されることを確認することです。そうしないと、それぞれのメソッドによって例外がスローされ、アプリケーションの実行が停止する可能性があります。これが入力データをチェックするプロセスです。ここで、「getHTML()」メソッドの新しいシグネチャを見てみましょう。これも「instanceof」演算子を使用しています:
$this->output.=($this->data instanceof HTMLElement)?$this->data-
>getHTML():$this->data;
ご覧のとおり、この場合、this 演算子は (X)HTML ウィジェット クラスの多態性機能を利用するのに非常に役立ちます。 $data 属性もウィジェットである場合、その "getHTML()" メソッドが正しく呼び出され、ネストされた Web 要素が表示されます。一方、それが単なる文字列の場合は、現在のクラスのすべての出力に直接追加されます。
この時点で、特定のオブジェクトが特定の型に属することを確認するための、PHP 5 の「instanceof」演算子の使用法を理解できたかもしれません。この記事でわかるように、PHP 5 でオブジェクト型を強制することは、実際には非常に簡単な作業です。現時点では、理解を深めるために、このメソッドを使用して PHP アプリケーション内のオブジェクトをフィルターする例を作成することをお勧めします。
5. まとめ
この記事では、PHP 5 の「instanceof」演算子を使用して入力オブジェクトの型を確認する方法を学びました。ただし、私が示した方法は唯一のものではありません。後の記事では、オブジェクトの型指定を強制するもう 1 つの方法である、優れた「型ヒント」機能を PHP 5 に実装する方法を説明します。
著者: Zhu Xianzhong Compiler 出典: Tianji Development