php5|オブジェクト
要旨】現在開発中のPHP5のオブジェクト指向機能が大幅に強化されました。次世代の PHP はどのような言語になるのでしょうか?現在リリースされているPHP5のベータ版について詳しく解説していきます。
(1) Zend 2.0 の誕生
現在、PHP4 で使用されている基本的な文法は、Zend エンジンと呼ばれるスクリプト編集エンジンです。これが、PHP3の改良として生まれた言語であるPHP4の優れた機能の理由の1つです。 PHP4 は本来の目的に基づいて PHP3 に比べてパフォーマンスが大幅に向上しており、ネットワーク プログラミングの世界で大きなシェアを占めていると誰もが信じてきました。
Zend エンジンを開発した Zend 社は、PHP3 の主な開発者である Zeev Suraski 氏と Andi Gutmans 氏が PHP4 の開発中に設立した会社を合併しました。 Zend の名前は、Zeev と Andi の名前を組み合わせたものです。 Zend のビジネス モデルは、Zend エンジンの PHP コアを継続的にオープンソースで提供すると同時に、周辺製品の開発と販売のメリットを増大させることです。オープンソース ソフトウェアに基づくビジネスは、世界中の苦境に立たされている企業の中でも比較的良い典型例であると考えられています。
■PHP4の限界
PHP4の成功により、このアプリケーションの適用範囲は徐々に広がっています。エンタープライズレベルの目的で PHP を使用するという話があります。そのため、大規模なWebサイトを構築する場合、コードの再利用性が非常に悪いという問題があります。具体的には、PHP4 のオブジェクト指向のパフォーマンスが非常に低いため、Java などのテクノロジーの使用に慣れている技術者から多くの不満が寄せられています。
PHP4 のオブジェクト指向のパフォーマンスを徐々に向上させ、基本的な文法を大幅に変更するという開発者は、PHP の記述方法を更新するという開発目標を達成しました。
■Zend 2.0 開発開始
その後、Zend PHP センターの開発者は、2001 年 7 月に次世代 PHP 言語エンジンとして Zend 2.0 エンジンのアイデアを発表しました。 [Zend Engine バージョン 2.0: 機能の概要と設計]
(http://www.zend.com/engine2/ZendEngine-2.0.pdf) をターゲットにしながら、オブジェクト指向のパフォーマンスが大幅に強化されました。
現在の PHP4 Zend エンジンの拡張は、過去の PHP3 の拡張とまったく同じです。これは、新しい言語エンジンのメジャー バージョン番号を上げ、手法の目標を明確にし、開発チームから賞賛を受けることを意味します。
Ze2 の開発は、以前の Zend エンジンと同様、オープンソース モードで実行されます。 CVS では最新のソースコードが完全に公開されており、オープンな開発者向けなので開発に関する議論が非常に活発です。
現在、PHPの次期バージョンであるPHP5にZe2が採用されることが決定しました。最終的なリリース時期はまだ決定されていませんが、2003 年 4 月 1 日に Zend Company がリリースしたニュースレターによると、現時点でベータ リリースになるはずです。
(2) PHP5の新機能
次に、PHP5の強化されたパフォーマンスを順番にご覧ください。 1 つ目は、最も重要なオブジェクト指向のパフォーマンスです。クラスのエンティティ特性が大幅に変更されています。ここで話しているのは、クラスの新しい機能についてのみです。
・オブジェクトの参照遷移はデフォルト(デフォルト)です
・プロパティへのアクセス制限の導入
・メソッドへのアクセス制限の導入
・抽象クラスと抽象メソッド
・インターフェース
・最終宣言
・名前空間
・クラス内定数
・クラス変数
・統合ビルダー
・デストラクター
・その他の付随機能
上記の内容は、2003年4月22日にCVSに記録されたバージョン情報に基づいています。正式リリース前には変更される可能性があります。
■オブジェクトのデフォルト参照遷移
PHP4では、変数$var1をクラスのエンティティオブジェクトとして使用する場合、 $var2 = $var1; の場合、$var2には$var1のコピーが代入されます。明らかに、$var2 が $var1 と同じオブジェクトを指すようにするには、$var2 =& $var1 として記述し、参照として & を追加する必要があります。
PHP5ではオブジェクト置換が自動参照遷移になります。言い換えれば、
$var2=$var1、両方とも同じオブジェクトを指します。 php4のようなコピーを取り込みたい場合は__clone()をインポートする方法を使います。
$var2 = $var1->__clone();ここでは、cloneの前に2つの連続した「_」が付いています
(これはクラスの実体の特徴に過ぎません)
■属性へのアクセス制限の導入
PHP4 クラスでは、プロパティやメソッドを含め、クラス内外のどこにでも制限なく自由にアクセスできます。したがって、ユーザーは属性に対する不注意な変更に対する保護がありません。
PHP5 では、C++ や Java と同様に、プライベート、プロテクト、パブリックの 3 つのレベルのアクセス制限が導入され、クラス設計者がプロパティとメソッドの使用を制限できるようになります。さまざまなアクセス制限の意味は次のとおりです。
・パブリック:クラス内外どこでも自由に参照・変更可能
・プライベート:このクラスのメソッドのみ参照・変更可能
・保護:このクラスと別のクラスで参照・変更可能このクラスを継承したクラス クラスのメソッドの参照や変更が可能です。また、継承したクラスにアクセス指定を記述することができます。
PHP4 の「var」は、これまでと同様に public と同じ意味を持ちます。例を挙げて、アクセス制限がどのように機能するかを見てみましょう。
PHP コード:------------------------------------------ --- ----------------------------------
class Hoge1 {
private $var1 = 'A';
protected $var2 = 'B';
protected $var3 = 'C';
function setLower() {
$this->var1 = 'a';
$this->var2 = 'b';
$this ->var3 = 'c';
}
function var1() {
return $this->var1;
}
function var2() {
return $this->var2;
}
function var3 () {
Return $this->var3;
}
}
-------------------------------- -- -----------------------------------------------
このクラスには 3 つの属性 $var1、$var2、$var3 があります。 $var1 はプライベートとして宣言され、$var2 と $var3 は保護されています。ここで
PHP コード:-------------------------- ---- ------------------------------------------------ ---
$hoge=new Hoge1;
echo'var1:'.$hoge->var1.”
n”
---------------------- ----- -------------------------------------- ----- ----------
外部からアクセスが許可されていないプライベートプロパティを参照しようとすると、次のエラーが表示されます:
致命的なエラー:プライベートにアクセスできません/path/ to/script.php の XX 行目の property hoge1::$var1
protected $var2 も同様です。
ただし、$hoge メソッドは private または protected ではないため、以下のコードは正常に動作し、内部の private 変数および protected 変数の値を返すことができます。
PHP コード:------------------------------------------ --- ----------------------------------
echo 'var1: ' $hoge->var1 () . "
n"; // var1: A
echo 'var2() . "
n"; ;var3 () . "
n"; // var3: C
$hoge->setLower();
echo ' . $hoge->var1() . var1: a
echo 'var2: ' . $hoge->var2() . "
n"; // var2: b
echo ' . $hoge->var3() . // var3: c
------------------------------------------ ----- ----------------------------------
第二に、見えるようになるためにprotected属性のステータスを取得して、Hoge1を継承したクラスHoge2を作成してみます
PHPコード:---------------------------- ----- -------------------------------------- ---
class Hoge2 extends Hoge1 {
public $var3 = '3';
function d_var1() {
return $this->var1;
}
function d_var2() {
return $this->var2 ;
}
function d_var3() {
Return $this->var3;
}
}
------------------------------------- -------- -------------------------------------- --------
クラス内 Hoge2 では、$var3 のみが public 宣言されています。プロパティが保護されている場合、サブクラスからのアクセスに対する制限は、サブクラスのプロパティ宣言によって決まります。 Hoge2では$var3をpublic宣言しているため、Hoge2の$var3にはどこからでもアクセス可能です(実体はHoge1の$var3です)。 Hoge1 では $var1 が private なので、Hoge2 のサブクラスには $var1 というプロパティが作られる可能性があり、Hoge1:: と $var1:: を明確に区別する必要があります。 $var1。
PHP コード:------------------------------------------ --- ----------------------------------
$hoge = new Hoge2;
echo 'var1: ' . $hoge->var1 . "
n"; // var1:
// echo 'var2: ' . "
n"; hoge->var3 . "
n"; // var3: 3
echo ' . $hoge->d_var1() . "
n" ; hoge->d_var2() . "
n"; // var2: B
echo ' . $hoge->d_var3() . "
n"; -------------------------------------------------- -- ------------------------
$hoge->var1 は Hoge1::var1 とは関係のない変数ですが、 var2 にはアクセス制限が保護されているため、表示されません。そのため、メソッドを渡さずに $var2 を直接参照すると、致命的なエラーが発生します。
■アクセス方法の制限を紹介します
上記と同様に、こちらもプライベート、プロテクト、パブリックの3種類に分けられます。
・パブリック:どこからでも呼び出すことができます
・プライベート:このクラスのメソッドからのみ呼び出すことができます
・プロテクト:このクラスとサブクラスのメソッドからのみ呼び出すことができます
ここでの意味はJavaと同じですと C++。混同しないでください。
■抽象クラスと抽象メソッド
Java と同じ抽象クラスと抽象メソッドをサポートします。抽象メソッドはメソッド名を呼び出す方法のみを提供しますが、エンティティを呼び出す方法は提供しません。さらに、抽象メソッドを保持するクラスは、クラス自体を抽象的に宣言する必要があります。抽象クラスのオブジェクトを直接作成しようとすると、以下のような致命的なエラーが発生します。
致命的なエラー: 抽象クラス ClassName をインスタンス化できません
エラーの実際の例は次のとおりです:
PHP コード:---------------------- -------------------------------------------------- -------
抽象クラス MyAbstract {
抽象パブリック関数 test();
パブリック関数 test2() {
echo "MyAbstract::test2() が呼び出されました。
n";
}
}
class MyImplement extends MyAbstract {
public function test() {
echo "MyImplement::test() called.
n";
}
}
$obj = new MyImplement;
$obj->test();
?>
------------------------------------------ ------ --------------------------------
■インターフェース
Javaと同じインターフェースをサポートします。インターフェースは、記述された外部呼び出し形式に適合するように設計および組み立てられます。
インターフェースエンティティは記録できません。対照的に、インターフェイスを実装するクラスは、インターフェイスのメソッドに対応するエンティティを保持する必要があります。さらに、クラスは複数のインターフェイスを実装できるため、多重継承が可能です。
PHP コード:------------------------------------------ --- ----------------------------------
interface Throwable {
public function getMessage();
}
インターフェース Serializable {
public function toString();
}
class MyExceptionimplements Throwable, Serializable {
public function getMessage() {
return 'this is MyException message';
}
public function toString() {
return 'MyException: これは MyException メッセージです';
}
}
$e = new MyException;
echo $e->getMessage();
echo $e->toString();
?>
------------------------------------------------ -- ----------------------------------
■final宣言
Javaと同様に、PHP5もfinalをサポートしています宣言。最終宣言がメソッドに追加された場合、このメソッドはサブクラスでオーバーロード (Override) されません。メソッドがfinal宣言されていてもサブクラスでオーバーロードされている場合、次のエラーが表示されます:
PHP code: ----------------------- -- ------------------------------------------------ -- -----
致命的なエラー: 最終メソッド fuga::foo() をオーバーライドできません
-------------------------- --- ---------------------------------------------- ---
エラーの例:
PHP コード:-------------------------------------- ---- ----------------------------------------
クラス フーガ{
final function foo() {
echo "これはfinal functionnです";
}
}
class Hoge extends Fuga {
function foo() {
echo "これはfinal functionnではありません";
}
}
? >
---------------------------------------------- --- ----------------------------------
(3) PHP5の新機能(続き)
PHP5 リリース計画
前回の記事で、「2003 年 4 月 1 日に ZEND 社が公開した情報によると、現在のものはベータ版リリースになるはずです。」と述べましたが、社内での議論の結果です。開発者は、ベータ版は初期段階のものであり、ベータ版リリースではない可能性があると考えています。
この傾向に興味がある人は、news://news.php.net/php.version5.dev で公開されている情報を参照してください。 372
このファイルでは、PHP5 Zend Engine 2のリリース計画は白紙に戻る一方、Zend Engine 2の開発は進行中です。 PHP5のリリースは実は「年末までに急ぐ」としている。
PHP5の新機能
それでは、前述したクラスの他の新機能をいくつか見てみましょう
■名前空間
PHP5は名前空間をサポートしています。したがって、クラス、変数、定数、関数を名前空間にロードできます。
PHP4 のスコープには、グローバル、関数内、クラス内の 3 つのカテゴリしかないため、注意しないとグローバル空間を簡単に「汚染」してしまうことに特に注意してください。名前空間を使用すると、パッケージ内の変数の名前空間を分離できるため、独立したパッケージを作成しやすくなるはずです。
使用例は以下の通りです:
PHPコード:------------------------------------- -------- --------------------------------------
名前空間This {
class Hoge {
}
const aConstant = 'この定数';
function aFunction() {}
var $aVariable = 'この変数';
}
$obj = new This::Hoge;
echo This ::aConstant . "
n ";
This::aFunction();
echo This::$aVariable . "
n";
-- ---------------------------------------------------- ------- -----
ネームスペース内のオブジェクトにアクセスしたい場合は、次のようにする必要があります:
ネームスペース名::オブジェクト名
ただし、PHP5 の名前空間は C++ と同じパターンに準拠していません。
■クラス内の定数
クラスおよび名前空間内で定数を定義するには、キーワード const を使用します。ここでは定数であるため、定数名の前に $ を追加する必要があります。クラス内の定数は、このクラスのグローバル定数よりも高い優先順位を持ちます。
ここでの const は予約なので、クラス名や関数名に const を使用する場合は必要な修正を行う必要があります。
PHP コード:------------------------------------------ --- ----------------------------------
define('constant_value', 'グローバル定数' );
class MyClass {
const constant_value = 'クラス定数';
function printConstant() {
print constant_value;
}
}
echo MyClass::constant_value "
n";
MyClass:rintConstant() ;
?>
------------------------------------------ ----- ----------------------------------
この例では、 MyClass:rintConstant( ) が表示されます 定数 constant_value の値ですが、 constant_value はグローバル空間とクラスの 2 か所に存在します。この場合、MyClass の constant_value が優先され、「クラス定数」として表示されます。
■オブジェクト変数
クラスがインスタンス化されていない場合でも、指定した値に従ってオブジェクト変数を正確に初期化できます。アクセス方法は以下の通りです:
クラス名::$変数名
PHPコード:---------------------------- ----- -------------------------------------- -----
class Hoge {
static $my_static = 5;
}
print Hoge::$my_static;
?>
--------------- ---------------------------------------------------- --------- ---------
■Unified Builder
オブジェクトを生成する際に、自動的に呼び出せるメソッドを「ビルダー」と呼びます。
PHP4のビルダーはクラス名と同じメソッド名です。これは Java や C++ と同じなので、慣れている人にとってはそれほど違和感はありません。ただし、サブクラスから親クラスのビルダーを呼び出したい場合は、PHP で親クラスの名前を明確に記述する必要があります。
PHPでは親クラスのコンストラクターを自動的に呼び出すことができないため、様々な状況が発生します。
PHP5では、クラス名が何であっても、__constructorというコンストラクタ名が一律に採用されており、__construct()というものはコンストラクタとして扱われます。
また、PHP4との互換性を考慮し、同じクラス名を持つ以前のビルダー名が存在する場合は、そのビルダーが先に使用されます。
PHP コード:------------------------------------------ --- ----------------------------------
class BaseClass {
function __construct() {
print " BaseClass コンストラクター内";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "サブクラス コンストラクター内";
}
}
$obj = new BaseClass( );
$obj = new SubClass();
?>
---------------------------- -------------------------------------------------- --
■デストラクター
ビルダーとは逆に、オブジェクトを解放する際に自動的に呼び出せるメソッドをデストラクターといいます。
PHP4はデストラクタをサポートしており、PHP終了時にregister_shutdown_function()という関数にログインすることで同様の実装方法しかありません。 PHP5 は、クラス内でオブジェクトが解放されるときのアクションを指定できるデストラクターを正式にサポートしています。
デストラクターは __destruct というメソッドです。オブジェクトの内部参照カウンタが 0 に達すると、__destruct() が呼び出され、オブジェクトによって使用されていたメモリが解放されます。
PHP コード:------------------------------------------ --- ----------------------------------
class MyDestructableClass {
function __construct() {
print " Inconstructorn";
$this->name = 'MyDestructableClass';
}
function __destruct() {
print '$this->name . "n";
}
}
$obj = new MyDestructableClass();
?>
-------------------------------------- ----- --------------------------------------
また、ビルダーの場合も同様で、親クラスのデストラクターを自動的に呼び出すことができません。必要に応じて、
parent::__destruct();
■Access
PHP4 の場合、存在しない属性にアクセスすると、システムはそれに対応する新しい属性を自動的に生成します。
PHP コード:------------------------------------------ --- ----------------------------------
class Hoge {
}
$obj = new Hoge ;
$obj->prop = "これは新しいプロパティです";
-------------------------------- -------------------------------------------------- --
上に示したように、存在しないプロパティに値が代入されると、その置換ポイントで新しいプロパティが自動的に生成されます。同様に、存在しないプロパティにアクセスしても、NULL 値を持つ変数に代入された場合と同様に、エラーは発生しません。
PHP5 で追加された追加機能は、任意の属性へのアクセスを制御する機能です。クラス内に __set() や __get() などのメソッドがある場合、上記のアクションの代わりにここのメソッドが呼び出されます。例:
PHP コード:------------------------------------------ ------ --------------------------------------
クラスHoge {
function __set($name, $value) {
print "($name, $value)nで__set()を呼び出す";
$this->$name = $value;
}
}
$obj = new Hoge;
$ obj->a = '123';
$obj->a = '456';
$obj->b = '789';
?>
- ---------------------------------------------------- --------- --------------------
ここでは、未定義のプロパティの置換メソッドとして__setメソッドを使用し、その値を値を表示した後、未定義のプロパティに代入されます。
PHP コード:------------------------------------------ --- ----------------------------------
$obj->a = '123';
------------------------------------------------- -- --------------------------------
この文を実行すると、この時点では属性aが存在しないため、したがって、代わりに __set メソッドが呼び出されます。
__set() は (a, 123) で呼び出されます
次に、
$obj->a = '456';
今回は属性 a が存在するため、$obj->a を再度代入します。したがって、__set は呼び出されず、値は通常どおり属性 a に代入されます。
$obj->b = '789';
今回は、最初のaの場合と同様に、値を別の属性bに代入し、
__set()が(b, 789 )で呼び出されます
__set メソッドとは異なり、存在しないプロパティへの参照がある場合、__get メソッドが呼び出されます。この 2 つを組み合わせて、プロパティへのアクセスを見てみましょう。実際、これを使用して、状況に応じて異なる応答を行うことができるクラスを作成できます。
PHP コード:------------------------------------------ --- ----------------------------------
class Hoge {
public $properties;
function __set ($name, $value) {
$this->properties[$name] = $value;
}
function __get($name) {
return $this->properties[$name];
}
}
$obj = new Hoge;
$obj->a = '123';
$obj->b = '456';
echo $obj->a;
echo $obj-> ;b ;
print_r($obj);
?>
--------------------------------- - ---------------------------------------------
でこの例では、クラス内のすべてのプロパティへのアクセスは $properties にロードされるため、追加するプロパティはオブジェクトに直接添付されません。これは理解しにくい例ですが、たとえば、この例の $properties への保存をファイルまたはデータベースへの保存に変更してみると面白いでしょう。実際、オブジェクトでは多くの複雑な操作を簡単に実装できます。
__set や __get とは少し異なりますが、次の例のように、オブジェクトのメソッドを呼び出す場合、__call を使用することもできます。
メソッド methodname がこのクラスに存在しない場合、通常は次のエラーが発生します:
致命的エラー: 未定義のメソッド Class::methodname() への呼び出し
ただし、このクラスに __call メソッドが存在する場合は、代わりに, __callが呼び出されます。 __call には 2 つのパラメータがあります。最初のパラメータは呼び出されるメソッドの名前で、2 番目のパラメータは呼び出されるパラメータの配列です。様々な利用方法があることを考慮し、以下の例以外にも様々な利用方法が考えられます。
PHP コード:------------------------------------------ --- ----------------------------------
クラス プロキシ {
private $object;
function __call ($name, $params) {
if (isset($this->object)) {
if (method_exists($this->object, $name)) {
return call_user_func_array(array($this- > object, $name), $params);
}
}
class Hoge {
function add($var1, $var2) {
return $var1 + $var2;
}
}
$p = new Proxy(new Hoge);
$result = $p ->add(1, 2);
echo "result: $result
n";
$result = $p->sub(5, 3) ;
echo "結果: $result
n";
?>