ホームページ >php教程 >php手册 >PHP オブジェクト指向の重要な知識 (3)

PHP オブジェクト指向の重要な知識 (3)

WBOY
WBOYオリジナル
2016-06-21 08:48:42842ブラウズ

1. 名前空間:

これは C++ の名前空間に非常に似ており、より多くのサードパーティ ライブラリを参照することによって引き起こされる名前の競合を回避するためのものです。名前空間を使用すると、2 つのクラスの名前が同じであっても、それらは異なる名前空間にあるため、正確に見つけて区別することができます。 PHP の名前空間構文を初めて見たとき、構文の点では C++ に非常によく似ていると感じましたが、実験のためにいくつかの小さな例を書いたとき、それらは依然として大きく異なることがわかりました。今後、特別にここに記録します。次のコードを参照してください:

コードをコピー

//Test2.php内

名前空間 nstesttest2;

クラス Test2 {

パブリック静的関数 printMe() {

print 'これは nstesttest2Test2::printSelf です。'."n";

}

}

//Test1.php内

名前空間 nstesttest1;

クラス Test1 {

パブリック静的関数 printMe() {

print 'これは nstesttest1Test1::printSelf です。'."n";

}

}

「Test2.php」が必要;

nstesttest2Test2::printMe();

コードをコピー

実行結果は次のとおりです:

bogon:TestPhp$ php Test1.php

PHP の致命的なエラー: クラス 'nstesttest1nstesttest2Test2' が /Users/liulei/PhpstormProjects/TestPhp/Test1.php の 13 行目に見つかりません

この結果は予想外でしょうか?その理由は何ですか?ほほー、PHP が名前空間を参照するとき、名前空間の最初の文字が先頭のスラッシュ () でない場合、自動的に相対名前空間として認識されることがわかりました。上記のコードでは、Test1 自体が配置されている名前空間が名前空間です。 nstesttest1 であるため、nstesttest2Test2::printMe() を使用して Test2::printMe() を呼び出すと、PHP は自動的にそれを nstesttest1nstesttest2Test2::printMe() に解決します。つまり、nstesttest2 は現在の名前空間内にあるとみなされます。この問題の修正は非常に簡単です。引用するときに先頭にスラッシュ () を追加するだけです。次の修正コードを参照してください:

コードをコピー

//Test2.php

名前空間 nstesttest2;

クラス Test2 {

パブリック静的関数 printMe() {

print 'これは nstesttest2Test2::printSelf です。'."n";

}

}

//Test1.php

名前空間 nstesttest1;

クラス Test1 {

パブリック静的関数 printMe() {

print 'これは nstesttest1Test1::printSelf です。'."n";

}

}

「Test2.php」が必要;

nstesttest2Test2::printMe();

コードをコピー

実行結果は次のとおりです:

bogon:TestPhp$ php Test1.php

これは nstesttest2Test2::printSelf です。

これを変更する別の方法は、PHP の名前空間での相対参照を表示することです。ここで、Test1 の名前空間を名前空間 nstest に変更できます。その他の変更については、次のコードの赤で強調表示された部分を参照してください。

コードをコピー

//Test2.php

名前空間 nstesttest2;

クラス Test2 {

パブリック静的関数 printMe() {

print 'これは nstesttest2Test2::printSelf です。'."n";

}

}

//Test1.php

名前空間 nstest;

クラス Test1 {

パブリック静的関数 printMe() {

print 'これは nstesttest1Test1::printSelf です。'."n";

}

}

「Test2.php」が必要;

test2Test2::printMe();

コードをコピー

実行結果は上記の正しい結果と同じです。最も重要な違いは、この例では PHP 名前空間内で相対位置を使用していることです。 C++ に精通している開発者は、PHP が提供するこのキーワードの機能はすべて同じであると考えています。後続のコードに接頭辞) を使用して、他の名前空間のクラスを参照します。具体的な文法規則については、以下の具体的なコードと主要なコメントを見てみましょう。

コードをコピー

//Test2.php

名前空間 nstesttest2;

クラス Test2 {

パブリック静的関数 printMe() {

print 'これは nstesttest2Test2::printSelf です。'."n";

}

}

//Test1.php

名前空間 nstesttest1;

クラス Test1 {

パブリック静的関数 printMe() {

print 'これは nstesttest1Test1::printSelf です。'."n";

}

}

「Test2.php」が必要;

//ここで特別な注意が必要なのは、nstesttest2 がすでに名前空間の絶対パス位置を示しており、先頭にスラッシュ () を追加する必要がないことです。

//さらに、ここには暗黙のルールがあり、test2 は名前空間のデフォルトのエイリアスを表し、その名前空間内のオブジェクトを参照する場合には test2 プレフィックスを追加する必要があります。

nstesttest2 を使用します;

test2Test2::printMe();

//ここで、次のような名前空間のエイリアスを明示的に指定することもできます:

nstesttest2 を test2_alias として使用します;

test2_aliasTest2::printMe();

コードをコピー

実行結果は次のとおりです:

bogon:TestPhp$ php Test1.php

これは nstesttest2Test2::printSelf です。

これは nstesttest2Test2::printSelf です。

最後に、PHP でグローバル名前空間を参照する方法を紹介します。次のコードと主要なコメントを参照してください。

コードをコピー

クラステスト {

パブリック静的関数 printMe() {

print 'これはグローバル名前空間 Test::printSelf です。'."n";

}

}

//次の 2 行のコードは同じオブジェクト、つまりグローバル名前空間の Test クラスを表します。ただし、名前空間の競合により最初のメソッドが PHP で使用できない場合は、

//コンパイラーはそれを正常に認識します。その後、2 番目のメソッドを使用して、グローバル名前空間内の Test クラスを参照することを PHP に明示的に通知できます。

テスト::printMe();

テスト::printMe();

コードをコピー

実行結果は次のとおりです:

bogon:TestPhp$ php Test1.php

これはグローバル名前空間 Test::printSelf です。

これはグローバル名前空間 Test::printSelf です。

2. 反省:

PHP のリフレクションには、Java の java.lang.reflect パッケージと同じ機能があります。さらに興味深いのは、多くのメソッドの名前付けと呼び出しメソッドも非常に似ていることです。これらは、クラス、クラス メソッド、メソッド パラメーターを分析できる一連の PHP 組み込みクラスで構成されています。ここで主に紹介するのは、一般的に使用される次の組み込みクラス (Reflection、RelectionClass、ReflectionMethod、ReflectionParameter、ReflectionProperty) です。それでは、ReflectionClass から始めて、サンプル コードと重要なコメントを示しながら、段階的に理解してみましょう:

コードをコピー

クラス TestClass {

public $publicVariable;

関数 publicMethod() {

print "これは publicMethod.n です";

}

}

関数 classInfo(ReflectionClass $c) {

$details = "";

//getName は実際のクラス名を返します。

$name = $c->getName();

if ($c->isUserDefined()) {

$details .= "$name はユーザー定義です。n";

}

if ($c->isInternal()) {

$details .= "$name は組み込み.n";

}

if ($c->isAbstract()) {

$details .= "$name は抽象クラスです。n";

}

if ($c->isFinal()) {

$details .= "$name は最終 class.n";

}

if ($c->isInstantiable()) {

$details .= "$name はインスタンス化できます。n";

} else {

$details .= "$name をインスタンス化できません。n";

}

$details を返す;

}

関数 classSource(ReflectionClass $c) {

$path = $c->getFileName();

$lines = @file($path);

//クラス定義コードの開始行と終了行を取得します。

$from = $c->getStartLine();

$to = $c->getEndLine();

$len = $to - $from + 1;

return implode(array_slice($lines,$from - 1,$len));

}

print "次はクラス情報です。n";

print classInfo(new ReflectionClass('TestClass'));

print "n次は​​ Class Source.n です";

print classSource(new ReflectionClass('TestClass'));

コードをコピー

実行結果は次のとおりです:

コードをコピー

bogon:TestPhp$ phpreflection_test.php

以下はクラス情報です。

TestClass はユーザー定義です。

TestClass はインスタンス化できます。

以下はクラスソースです。

クラス TestClass {

public $publicVariable;

関数 publicMethod() {

print "これは publicMethod.n です";

}

}

コードをコピー

コード例と重要なコメントを使用して、ReflectionMethod の学習の旅を続けましょう。

コードをコピー

クラス TestClass {

public $publicVariable;

関数 __construct() {

}

プライベート関数 privateMethod() {

}

関数 publicMethod() {

print "これは publicMethod.n です";

}

function publicMethod2(string $arg1, int $arg2) {

}

}

//この関数で使用される ReflectionMethod のメソッドは非常にシンプルで直感的であるため、詳細については説明しません。

関数 methodInfo(ReflectionMethod $m) {

$name = $m->getName();

$details = "";

if ($m->isUserDefined()) {

$details .= "$name はユーザー定義です。n";

}

if ($m->isInternal()) {

$details .= "$name は組み込み.n";

}

if ($m->isAbstract()) {

$details .= "$name は abstract.n";

}

if ($m->isPublic()) {

$details .= "$name は public.n";

}

if ($m->isProtected()) {

$details .= "$name は保護されています.n";

}

if ($m->isPrivate()) {

$details .= "$name は private.n";

}

if ($m->isStatic()) {

$details .= "$name は static.n";

}

if ($m->isFinal()) {

$details .= "$name は Final.n";

}

if ($m->isConstructor()) {

$details .= "$name はconstructor.nです";

}

if ($m->returnsReference()) {

$details .= "$name は参照を返します。n";

}

$details を返す;

}

関数メソッドSource(ReflectionMethod $m) {

$path = $m->getFileName();

$lines = @file($path);

$from = $m->getStartLine();

$to = $m->getEndLine();

$len = $to - $from + 1;

return implode(array_slice($lines, $from - 1, $len));

}

$rc = new ReflectionClass('TestClass');

$methods = $rc->getMethods();

print "以下はメソッド情報です。n";

foreach ($methods として $method) {

print methodInfo($method);

print "n-----------------------------n";

}

print "以下は Method[TestClass::publicMethod] source.n です";

print methodSource($rc->getMethod('publicMethod'));

コードをコピー

実行結果は次のとおりです:

コードをコピー

bogon:TestPhp$ phpreflection_test.php

以下はメソッド情報です。

__construct はユーザー定義です。

__construct はパブリックです。

__construct はコンストラクターです。

----------------------

privateMethod はユーザー定義です。

privateMethod はプライベートです。

----------------------

publicMethod はユーザー定義です。

publicMethod はパブリックです。

----------------------

publicMethod2 はユーザー定義です。

publicMethod2 はパブリックです。

----------------------

以下は Method[TestClass::publicMethod] のソースです。

関数 publicMethod() {

print "これは publicMethod.n です";

}

コードをコピー

引き続き、メンバー関数のパラメーター情報を表す ReflectionParameter を見てみましょう。引き続きコードを見てみましょう。

コードをコピー

クラス ParamClass {

}

クラス TestClass {

関数 publicMethod() {

print "これは publicMethod.n です";

}

function publicMethod2(ParamClass $arg1, &$arg2, $arg3 = null) {

}

}

関数 paramInfo(ReflectionParameter $p) {

$details = "";

//ここでの $declaringClass は TestClass と等しくなります。

$declaringClass = $p->getDeclaringClass();

$name = $p->getName();

$class = $p->getClass();

$position = $p->getPosition();

$details .= "$$name の位置は $position.n";

if (!empty($class)) {

$classname = $class->getName();

$details .= "$$name は $classname オブジェクトである必要があります";

}

if ($p->isPassedByReference()) {

$details .= "$$name は参照によって渡されます。n";

}

if ($p->isDefaultValueAvailable()) {

$def = $p->getDefaultValue();

$details .= "$$name のデフォルトは $defn";

}

$details を返す;

}

$rc = new ReflectionClass('TestClass');

$method = $rc->getMethod('publicMethod2');

$params = $method->getParameters();

foreach ($params as $p) {

print paramInfo($p)."n";

}

コードをコピー

実行結果は次のとおりです:

コードをコピー

bogon:TestPhp$ phpreflection_test.php

$arg1 の位置は 0 です。

$arg1 は ParamClass オブジェクトである必要があります

$arg2 の位置は 1 です。

$arg2 は参照によって渡されます。

$arg3 の位置は 2 です。

$arg3 のデフォルト値:

コードをコピー

上記で紹介したのは、PHPが提供するリフレクションAPIを介して任意のクラスの固有情報をトラバースするというものですが、実はJavaなど他の言語が提供するリフレクション関数と同様に、PHPでも呼び出し方法をサポートしています。ここでは主に 2 つのメソッドに適用されます。1 つはオブジェクト インスタンスを作成する ReflectionClass::newInstance() で、もう 1 つはオブジェクトに基づいてメソッドを実行する ReflectionMethod::invoke() です。インスタンス名とメソッド名。次のコードを参照してください:

コードをコピー

クラス TestClass {

プライベート $privateArg;

関数 __construct($arg) {

$this->privateArg = $arg;

}

関数 publicMethod() {

print '$privateArg = '.$this->privateArg."n";

}

関数 publicMethod2($arg1, $arg2) {

print '$arg1 = '.$arg1.' $arg2 = '.$arg2."n";

}

}

$rc = new ReflectionClass('TestClass');

$testObj = $rc->newInstanceArgs(array('これはプライベート引数です。'));

$method = $rc->getMethod('publicMethod');

$method->invoke($testObj);

$method2 = $rc->getMethod('publicMethod2');

$method2->invoke($testObj,"hello","world");

コードをコピー

実行結果は次のとおりです:

bogon:TestPhp$ phpreflection_test.php

$privateArg = これはプライベート引数です。

$arg1 = こんにちは $arg2 = 世界

実際、ReflectionClass、ReflectionMethod、および ReflectionParameter は、より直感的に PHP Reflection API を学習して理解できるように、より多くの利用可能なメソッドを提供します。次のコード例を読めば、将来クラス関連の関数を使用する必要がある場合、メンバー関数の情報は ReflectionMethod から取得し、メソッドのパラメーター情報を取得する必要があることがよくわかると思います。 ReflectionParameter から取得する必要があります。

注: このブログに記録されている知識ポイントは、私が PHP を学習する過程で遭遇した、または本当に覚えておく必要がある他のオブジェクト指向言語と比較した PHP のユニークな側面の一部です。今後の参考にさせていただくポイント。深くはありませんが、皆さんと共有できればと思っています。



声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。