PHP V5 の新しい言語機能を使用すると、コードの保守性と信頼性が大幅に向上します。この記事を読むことで、これらの新機能を利用して PHP V4 で開発されたコードを PHP V5 に移行する方法がわかります。
PHP V5 は、PHP V4 に基づいて大幅な改良を加えています。新しい言語機能により、信頼性の高いクラス ライブラリの構築と保守が容易になります。さらに、標準ライブラリを書き直すことで、PHP を Java™ プログラミング言語などの他の Web 表現とより一致させることができました。 PHP の新しいオブジェクト指向機能のいくつかを見て、既存の PHP V4 コードを PHP V5 に移行する方法を学びましょう。
まず、新しい言語機能と PHP の作成者が PHP V4 でオブジェクトを作成する方法をどのように変更したかを見てみましょう。 V5 のアイデアは、Web アプリケーション開発用の工業用に強力な言語を作成することでした。これは、PHP V4 の制限を理解し、他の言語 (Java、C#、C++、Ruby、Perl など) から既知の優れた言語アーキテクチャを抽出し、それらを PHP に組み込むことを意味します。
最初の最も重要な新機能は、クラス メソッドとインスタンス変数 (public、protected、および private キーワード) のアクセス保護です。 この新しい機能により、クラス設計者はクラスの固有プロパティの制御を維持しながら、どのクラスがアクセス可能でどのクラスがアクセスできないかをクラスのユーザーに伝えることができます。
PHP V4 では、すべてのコードが公開されます。 PHP V5 では、クラス設計者は、どのコードが外部に表示されるか (パブリック)、どのコードがクラス内でのみ表示されるか (プライベート)、またはクラスのサブクラスにのみ表示されるか (プロテクト) を宣言できます。これらのアクセス制御がないと、これらのクラスのユーザーが間違ったメソッドを使用したり、プライベート メンバー変数であるべきコードにアクセスしたりする可能性があるため、大規模なチームでコードを開発したり、コードをライブラリとして配布したりすることが妨げられます。
もう 1 つの大きな新機能は、コントラクト プログラミングを可能にするキーワード インターフェイスとアブストラクトです。コントラクト プログラミングとは、あるクラスが別のクラスにコントラクトを提供することを意味します。つまり、「これが私がやろうとしていることです。あなたはそれがどのように行われるかを知る必要はありません。」ということです。 インターフェースを実装するすべてのクラスは、この規約に従います。インターフェイスのすべてのユーザーは、インターフェイスで指定されたメソッドのみを使用することに同意します。後で説明するように、abstract キーワードを使用すると、インターフェイスの操作が非常に簡単になります。
これら 2 つの主要な機能 (アクセス制御とコントラクト プログラミング) により、大規模なコーダー チームが大規模なコード ベースをよりスムーズに操作できるようになります。これらの機能により、IDE は言語インテリジェントな機能の豊富なセットを提供することもできます。この記事では、移行に関するいくつかの問題に対処するだけでなく、これらの新しい主要な言語機能の使用方法についても時間をかけて説明します。
アクセス制御
新しい言語機能をデモンストレーションするために、Configuration というクラスを使用しました。この単純なクラスには、Web アプリケーションの構成項目 (たとえば、images ディレクトリへのパス) が含まれています。理想的には、この情報はファイルまたはデータベースに存在します。リスト 1 は簡略化されたバージョンを示しています。
リスト 1. access.php4
<?php
クラス構成
{
var $_items = array()
関数構成();
$this->_items[ 'imgpath' ] = '画像';
}
関数 get( $key ) {
$this->_items[ $key ] を返します。
}
$
c = 新しい構成();
echo( $c->get( 'imgpath' )."n" );
?>
これは完全にオーソドックスな PHP V4 クラスです。メンバー変数は構成項目のリストを保持し、コンストラクターが項目をロードし、get() という名前のアクセス・メソッドが項目の値を返します。
スクリプトを実行すると、コマンド ラインに次のコードが表示されます:
%php access.php4
画像
%
とても良い!この結果は、コードが正常に実行され、imgpath 構成項目の値が正常に設定および読み取られたことを意味します。
このクラスを PHP V5 に変換する最初のステップは、コンストラクターの名前を変更することです。 PHP V5 では、オブジェクト (コンストラクター) を初期化するメソッドは __construct と呼ばれます。この小さな変化を以下に示します。
リスト 2. access1.php5
<?php
クラス構成
{
var $_items = array()
関数 __construct();
$this->_items[ 'imgpath' ] = '画像';
}
関数 get( $key ) {
$this->_items[ $key ] を返します。
}
$
c = 新しい構成();
echo( $c->get( 'imgpath' )."n" );
?>
今回の変更はそれほど大きなものではありません。 PHP V5 規約に移行したばかりです。次のステップでは、クラスにアクセス制御を追加して、クラスのユーザーが $_items メンバー変数を直接読み書きできないようにします。この変更を以下に示します。
リスト 3. access2.php5
<?php
クラス構成
{
プライベート $_items = array();
パブリック関数 __construct() {
$this->_items[ 'imgpath' ] = '画像';
}
パブリック関数 get( $key ) {
$this->_items[ $key ] を返します。
}
$
c = 新しい構成();
echo( $c->get( 'imgpath' )."n" );
?>
このオブジェクトのユーザーが項目配列に直接アクセスすると、配列はプライベートとしてマークされているため、アクセスは拒否されます。幸いなことに、ユーザーは get() メソッドが待望の読み取り権限を提供することを発見しました。
保護されたアクセス許可の使用方法を説明するには、Configuration クラスを継承する別のクラスが必要です。私はそのクラスを DBConfiguration と呼び、このクラスがデータベースから構成値を読み取るものと想定しました。この設定を以下に示します。
リスト 4. access3.php
<?php
クラス構成
{
protected $_items = array();
パブリック関数 __construct() {
$this->load();
}
保護された関数load() { }
パブリック関数 get( $key ) {
$this->_items[ $key ] を返します。
}
DBConfiguration
は Configuration を拡張します
{
保護された関数load() {
$this->_items[ 'imgpath' ] = '画像';
}
$
c = 新しい DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
このリストは、保護されたキーワードの正しい使用法を示しています。基本クラスは、load() という名前のメソッドを定義します。このクラスのサブクラスは、load() メソッドをオーバーライドして、項目テーブルにデータを追加します。 load() メソッドはクラスとそのサブクラスの内部にあるため、このメソッドはすべての外部コンシューマに表示されるわけではありません。キーワードがすべてプライベートである場合、load() メソッドをオーバーライドすることはできません。
このデザインはあまり好きではありませんが、DBConfiguration クラスに item 配列へのアクセスを与える必要があったため、これを選択しました。他のサブクラスが追加されたときに、それらのクラスが項目配列を維持する方法を知る必要がないように、項目配列をすべて Configuration クラスによって維持し続けたいと考えています。以下の変更を加えました。
リスト 5. access4.php5
<?php
クラス構成
{
プライベート $_items = array();
パブリック関数 __construct() {
$this->load();
}
保護された関数load() { }
保護された関数 add( $key, $value ) {
$this->_items[ $key ] = $value;
}
パブリック関数 get( $key ) {
$this->_items[ $key ] を返します。
}
DBConfiguration
は Configuration を拡張します
{
保護された関数load() {
$this->add( 'imgpath', 'images' );
}
$
c = 新しい DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
サブクラスが protected add() メソッドを使用して構成項目をリストに追加するため、項目の配列をプライベートにできるようになりました。 Configuration クラスは、そのサブクラスに関係なく、構成アイテムの保存方法と読み取り方法を変更できます。 load() メソッドと add() メソッドが同じ方法で実行される限り、サブクラス化に問題はありません。
私にとって、追加されたアクセス制御が、PHP V5 への移行を検討する主な理由です。それは単に Grady Booch が PHP V5 が 4 つの主要なオブジェクト指向言語の 1 つであると言ったからでしょうか?いいえ、私はかつて、すべてのメソッドとメンバーがパブリックとして定義されている 100KLOC C++ コードを保守するタスクを引き受けたからです。これらの定義をクリーンアップするのに 3 日かかりました。その過程で、エラーの数が大幅に減少し、保守性が向上しました。なぜ?アクセス制御がなければ、オブジェクトが他のオブジェクトをどのように使用するかを知ることができず、どのような障害を乗り越えるべきかが分からなければ変更を加えることができないからです。 C++ では、少なくともコンパイラはまだ利用可能です。 PHP にはコンパイラが付属していないため、この種のアクセス制御はさらに重要になります。
コントラクト プログラミング
PHP V4 から PHP V5 に移行する際に活用すべき次の重要な機能は、インターフェイス、抽象クラス、およびメソッドを介したコントラクト プログラミングのサポートです。リスト 6 は、PHP V4 のプログラマーが、interface キーワードをまったく使用せずに基本的なインターフェイスを構築しようとしたバージョンの Configuration クラスを示しています。
リスト 6.interface.php4
<?php
クラスI構成
{
関数 get( $key ) { }
クラス Configuration は IConfiguration を拡張し
ます
{
var $_items = array()
関数構成();
$this->load();
}
関数ロード() { }
関数 get( $key ) {
$this->_items[ $key ] を返します。
}
DBConfiguration
は Configuration を拡張します
{
関数ロード() {
$this->_items[ 'imgpath' ] = '画像';
}
$
c = 新しい DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
このリストは、Configuration クラスまたは派生クラスによって提供されるすべてのインターフェイスを定義する小さな IConfiguration クラスから始まります。このインターフェイスは、クラスとそのすべてのユーザー間の契約を定義します。この契約では、IConfiguration を実装するすべてのクラスには get() メソッドが装備されている必要があり、IConfiguration のすべてのユーザーは get() メソッドのみを使用する必要があると規定されています。
以下のコードは PHP V5 で実行されますが、以下に示すように提供されているインターフェイス システムを使用することをお勧めします。
リスト 7.interface1.php5
<?php
インターフェイス IConfiguration
{
関数 get( $key );
クラス Configuration は IConfiguration を実装し
ます
{
...
DBConfiguration
は Configuration を拡張します
{
...
$
c = 新しい DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
一方では、読者は実行ステータスをより明確に理解できますが、他方では、単一のクラスが複数のインターフェイスを実装できます。リスト 8 は、Configuration クラスを拡張して PHP の内部インターフェースである Iterator インターフェースを実装する方法を示しています。
リスト 8.interface2.php5
<?php
インターフェース IConfiguration {
...
クラス Configuration は IConfiguration、Iterator を実装します
。
{
プライベート $_items = array();
パブリック関数 __construct() {
$this->load();
}
保護された関数load() { }
保護された関数 add( $key, $value ) {
$this->_items[ $key ] = $value;
}
パブリック関数 get( $key ) {
$this->_items[ $key ] を返します。
パブリック関数 rewind() { リセット($this->_items)
}
パブリック関数 current() { return current($this->_items); }
パブリック関数 key() { return key($this->_items) }
パブリック関数 next() { return next($this->_items); }
public function valid() { return ( $this->current() !== false );
クラス DBConfiguration は構成を拡張します
{
...
$
c = 新しい DBConfiguration();
foreach( $c as $k => $v ) { echo( $k." = ".$v."n" );
?>
Iterator インターフェイスを使用すると、任意のクラスをそのコンシューマーの配列のように見せることができます。スクリプトの最後にあるように、foreach 演算子を使用して、Configuration オブジェクト内のすべての構成項目を繰り返すことができます。 PHP V4 にはこの機能はありませんが、アプリケーション内でさまざまな方法でこの機能を使用できます。
インターフェイス メカニズムの利点は、メソッドを実装する必要がなく、コントラクトを迅速にまとめることができることです。最後の段階ではインターフェイスを実装します。ここでは、指定されたすべてのメソッドを実装する必要があります。 PHP V5 のもう 1 つの便利な新機能は抽象クラスです。これにより、基本クラスを使用してインターフェイスのコア部分を実装し、そのインターフェイスを使用してエンティティ クラスを作成することが簡単になります。
抽象クラスのもう 1 つの用途は、基本クラスがインスタンス化されない複数の派生クラスの基本クラスを作成することです。たとえば、DBConfiguration と Configuration が同時に存在する場合、DBConfiguration のみを使用できます。 Configuration クラスは単なる基本クラス、つまり抽象クラスです。したがって、次に示すように、abstract キーワードを使用してこの動作を強制できます。
リスト 9. abstract.php5
<?php
抽象クラスの構成
{
protected $_items = array();
パブリック関数 __construct() {
$this->load();
}
抽象保護関数load();
パブリック関数 get( $key ) {
$this->_items[ $key ] を返します。
}
DBConfiguration
は Configuration を拡張します
{
保護された関数load() {
$this->_items[ 'imgpath' ] = '画像';
}
$
c = 新しい DBConfiguration();
echo( $c->get( 'imgpath' )."n" );
?>
現在、システムはクラスが抽象的で不完全であると見なすため、Configuration 型のオブジェクトをインスタンス化しようとするとエラーになります。
静的メソッドと静的メンバー
PHP V5 のもう 1 つの重要な新機能は、クラスの静的メンバーと静的メソッドのサポートです。この機能を利用することで、人気のシングルトンパターンを利用することができます。アプリケーションには構成オブジェクトが 1 つだけあればよいため、このパターンは Configuration クラスに最適です。
リスト 10 は、PHP V5 バージョンの Configuration クラスをシングルトンとして示しています。
リスト 10. static.php5
<?php
クラス構成
{
プライベート $_items = array();
静的プライベート $_instance = null;
静的パブリック関数 get() {
if ( self::$_instance == null )
self::$_instance = 新しい構成();
self::$_instance を返します。
プライベート関数 __construct()
{
$this->_items[ 'imgpath' ] = '画像';
}
パブリック関数 __get( $key ) {
$this->_items[ $key ] を返します。
}
echo
( Configuration::get()->{ 'imgpath' }."n" );
?>
static キーワードにはさまざまな用途があります。単一タイプのすべてのオブジェクトのグローバル データにアクセスする必要がある場合は、このキーワードの使用を検討してください。
マジック メソッド
PHP V5 のもう 1 つの大きな新機能は、マジック メソッドのサポートです。これにより、オブジェクトがオブジェクトのインターフェイスを迅速に変更できるようになります。たとえば、Configuration オブジェクト内の各構成項目にメンバー変数を追加できます。 get() メソッドを使用する必要はありません。以下に示すように、特定の項目を検索して配列として扱うだけです。
リスト 11. magic.php5
<?php
クラス構成
{
プライベート $_items = array()
関数 __construct()
;
$this->_items[ 'imgpath' ] = '画像';
}
関数 __get( $key ) {
$this->_items[ $key ] を返します。
}
$
c = 新しい構成();
echo( $c->{ 'imgpath' }."n" );
?>
この例では、ユーザーがオブジェクトのメンバー変数を検索するたびに呼び出される新しい __get() メソッドを作成しました。メソッド内のコードは、項目の配列を使用して値を検索し、そのキーワード専用のメンバー変数があるかのようにその値を返します。オブジェクトが配列であると仮定すると、スクリプトの最後で、Configuration オブジェクトの使用が imgpath の値を見つけるのと同じくらい簡単であることがわかります。
PHP V4 から PHP V5 に移行する場合は、PHP V4 では完全に使用できないこれらの言語機能に注意し、クラスを再検証してそれらがどのように使用できるかを確認する必要があります。
例外については
、PHP V5 の新しい例外メカニズムを紹介してこの記事を終了します。例外は、エラー処理についてまったく新しい考え方を提供します。すべてのプログラムでは、ファイルが見つからない、メモリ不足などのエラーが必然的に発生します。例外が使用されない場合は、エラー コードを返す必要があります。以下の PHP V4 コードをご覧ください。
リスト 12. file.php4
<?php
関数 parseLine( $l )
{
// ...
return array( 'error' => 0,
data => array() // ここにデータが入ります
);
関数
readConfig( $path )
{
if ( $path == null ) は -1 を返します。
$fh = fopen( $path, 'r' );
if ( $fh == null ) は -2 を返します;
while( !feof( $fh ) ) {
$l = fgets( $fh );
$ec = parseLine( $l );
if ( $ec['error'] != 0 ) $ec['error'] を返します。
fclose
( $fh );
0を返します。
$
e = readConfig( 'myconfig.txt' );
if ( $e != 0 )
echo( "エラーが発生しました (".$e.")n" );
?>
この標準ファイル I/O コードは、ファイルを読み取り、データを取得し、エラーが発生した場合はエラー コードを返します。このスクリプトに関して 2 つの質問があります。 1つ目はエラーコードです。これらのエラーコードは何を意味するのでしょうか?これらのエラー コードの意味を調べるには、これらのエラー コードを意味のある文字列にマップする別のシステムを作成する必要があります。 2 番目の問題は、parseLine の戻り結果が非常に複雑であることです。データを返すだけで十分ですが、実際にはエラー コードとデータを返す必要があります。ほとんどのエンジニア (私も含めて) は、エラーの管理が難しいため、怠けてデータを返してエラーを無視することがよくあります。
リスト 13 は、例外を使用する場合のコードがいかに明確であるかを示しています。
リスト 13. file.php5
<?php
関数 parseLine( $l )
{
// 解析してスローし、無効な場合は例外をスローします
戻り配列(); // データ
関数
readConfig( $path )
{
if ( $path == null )
新しい例外をスローします( '不正な引数' );
$fh = fopen( $path, 'r' );
if ( $fh == null )
throw new Exception( 'ファイルを開けませんでした' );
while( !feof( $fh ) ) {
$l = fgets( $fh );
$ec = parseLine( $l );
fclose
( $fh );
}
試す {
readConfig( 'myconfig.txt' );
} catch(例外 $e) {
エコー( $e );
}
?>
例外にはエラーの説明テキストが含まれているため、エラー コードについて心配する必要はありません。また、parseLine から返されたエラー コードを追跡する方法を考える必要もありません。エラーが発生した場合、関数はエラーをスローするだけです。スタックは、スクリプトの下部にある最も近い try/catch ブロックまで拡張されます。
例外はコードの書き方に革命をもたらします。エラー コードとマッピングの煩わしさを管理する代わりに、処理したいエラーに集中できます。このようなコードは読みやすく、保守しやすく、通常は利益をもたらすため、エラー処理を追加することをお勧めします。
結論
新しいオブジェクト指向機能と例外処理の追加は、コードを PHP V4 から PHP V5 に移行する強力な理由となります。ご覧のとおり、アップグレードプロセスは難しくありません。 PHP V5 まで拡張された構文は、PHP とまったく同じように感じられます。はい、これらの構文は Ruby などの言語から来ていますが、組み合わせて非常にうまく機能すると思います。そして、これらの言語は、PHP の範囲を小規模サイト用のスクリプト言語からエンタープライズ レベルのアプリケーションを完成させるために使用できる言語に拡張します。