データベースを操作すると同時に次の要件を満たすクラスを作成する必要があるとします。
① SqlHelper クラスはインスタンスを 1 つだけ持つことができます (それ以上は持てません)
② SqlHelper クラスはインスタンスを作成できる必要がありますこのインスタンスは単独で
③ それをシステム全体に単独で提供する必要がある この例を示します。つまり、複数のオブジェクトがメモリ領域を共有します。たとえば、オブジェクト A が特定の属性値を設定すると、オブジェクト B と C もこれらにアクセスできます。属性値 (最後の例はこの問題をよく示しています)
1 <?php 2 class SqlHelper{ 3 private static $_instance; 4 public $_dbname; 5 private function __construct(){ 6 7 } 8 public function getDbName(){ 9 echo $this->_dbname;10 }11 public function setDbName($dbname){12 $this->_dbname=$dbname;13 }14 public function clear(){15 unset($this->_dbname);16 }17 18 }19 $sqlHelper=new SqlHelper();//打印:Fatal error: Call to private SqlHelper::__construct() from invalid context 20 ?>
上記の SqlHelper クラスは、コンストラクターをプライベートに設定しているため、独自のクラスの外部からインスタンスを作成できません。 new SqlHelper() を介してクラスの外部から使用することはできません。強制的に使用すると、次のエラーが報告されます:
致命的エラー: 無効なコンテキストからプライベート SqlHelper::__construct() を呼び出します
致命的エラー: プライベート コンストラクター SqlHelper を呼び出しますコンテキストから ::__construct()
に従ってください。 以前は、クラスの外で直接 new 演算子を使用してクラスをインスタンス化するという考え方がありましたが、ここではコンストラクターが private に設定されているため、private であることがわかります。メンバー属性または関数はクラス内でのみアクセスできるため、SqlHelper クラス内に別の関数 (例: getInstance()) を作成できます。getInstance() 関数の主な目的は、インスタンスを作成することです。 SqlHelper クラスの例:
1 <?php 2 class SqlHelper{ 3 private $_instance; 4 //......省略 5 public function getInstance(){ 6 $this->_instance=new SqlHelper(); 7 } 8 //......省略 9 }10 ?>
しかし、問題が発生します。
① getInstance() を呼び出す前に SqlHelper オブジェクトをインスタンス化していないため、オブジェクトを通じて getInstance() 関数を呼び出すことができません。 getInstance を呼び出すときにオブジェクトがインスタンス化されていないため、getInstance 関数で $this を使用すると間違いなくエラーが報告されます (致命的なエラー: オブジェクト コンテキスト内にないときに $this を使用する)
それでは、どうすれば解決できるでしょうか?
解決策: getInstance() メソッドを静的として設定できます。静的の定義によれば、$_instance を静的として設定するだけで呼び出すことができます。したがって、この方法はまさに私たちにとって最適な方法です。
1 <?php 2 class SqlHelper{ 3 private static $_instance; 4 private function __construct(){ 5 echo "构造函数被调用"; 6 } 7 //......省略 8 public static function getInstance(){ 9 if (self::$_instance===null) {10 // self::$_instance=new SqlHelper();//方式一11 self::$_instance=new self();//方式二 12 }13 return self::$_instance;14 }15 //......省略16 }17 $sqlHelper=SqlHelper::getInstance();//打印:构造函数被调用18 ?>
getInstance 関数で現在のメモリに現在のクラスのインスタンスがあるかどうかを判断し、存在しない場合はインスタンス化し、存在する場合はオブジェクト ハンドルを返します。次に、オブジェクト ハンドルを直接返します
この時点で、完全なコードは次のとおりです:
1 <?php 2 class SqlHelper{ 3 private static $_instance; 4 public $_dbname; 5 private function __construct(){ 6 7 } 8 //getInstance()方法必须设置为公有的,必须调用此方法 9 public static function getInstance(){10 //对象方法不能访问普通的对象属性,所以$_instance需要设为静态的11 if (self::$_instance===null) {12 // self::$_instance=new SqlHelper();//方式一 13 self::$_instance=new self();//方式二 14 }15 return self::$_instance;16 }17 public function getDbName(){18 echo $this->_dbname;19 }20 public function setDbName($dbname){21 $this->_dbname=$dbname;22 }23 }24 // $sqlHelper=new SqlHelper();//打印:Fatal error: Call to private SqlHelper::__construct() from invalid context 25 $A=SqlHelper::getInstance();26 $A->setDbName('数据库名');27 $A->getDbName();28 // unset($A);//移除引用29 $B=SqlHelper::getInstance();30 $B->getDbName();31 $C=SqlHelper::getInstance();32 $C->getDbName();33 34 ?>
上記のコードの実行結果:
Database name//$A->getDbName();
データベース名//$B ->getDbName();
つまり、オブジェクト A、B、C は実際には同じオブジェクト インスタンスを使用し、同じオブジェクト インスタンスにアクセスしますしたがって、たとえ unset($A) であっても、オブジェクト B と C は getDbName() メソッドを通じて「データベース名」を出力できます。
unset($A) は、実際にはオブジェクト A を特定のメモリ アドレス (オブジェクトのインスタンス) のアドレス) は切断されており、オブジェクト B とオブジェクト C とは何の関係もありません。