CakePHPでシングルトンパターンとは?

このQ&Aのポイント
  • CakePHPでシングルトンパターンを使用してインスタンスを使いまわす方法について
  • シングルトンパターンを実装するための設定が足りない可能性がある
  • Testクラスを呼び出す際にインスタンスが新しく生成されてしまう問題が発生している
回答を見る
  • ベストアンサー

CakePHPでシングルトンパターン

CakePHPでシングルトンパターンで、インスタンスを使いまわしたいのですが、 うまく動作しません。 以下のようなプログラムですが、何か設定が足りないのでしょうか class Test{   public static $instance = null;   public function __construct(){}   public function getInstance(){    if(is_null(Test::$instance)){     Test::$instance = new Test();    }    return Test::$instance;   } } 上記クラスを以下のように呼び出しております。 $instance = Test::getInstance(); 何度やっても、インスタンスが新しく生成されてしまします。 良い方法がございましたら、ご教授下さい。

  • PHP
  • 回答数7
  • ありがとう数5

質問者が選んだベストアンサー

  • ベストアンサー
noname#244856
noname#244856
回答No.6

隠蔽されていることから逆に考えてしまえば、そもそもシングルトンを使う必要がないということですね。シングルトンは内部状態を持ち、テストが書きにくいため、特にフレームワークを導入していて自動テストを理想とするような開発では嫌われる傾向にあります。無理して使う必要はないでしょう。

その他の回答 (6)

  • mpro-gram
  • ベストアンサー率74% (170/228)
回答No.7

No4回答へのお礼の記載に関して >1度作成したインスタンスは、Apacheを再起動するまでは、作成しないようにすることはCakePHPでは可能なのでしょうか phpでは、無理です。 php の実行自体が 1リクエスト1実行 で完了します(完了時メモリ解放)。メモリー上のオブジェクトのユーザー間共有は無理です。1ユーザーの複数リクエストでさえ、sessionにでも保存しない限り共有できません。 「情報共有」の観点では、保存状態がオブジェクトである必要はないと考える、phpのシングルトンはその目的には使えないし。同じ情報が各リクエストにおいて再生されればいいのですよね。 cakePHPならデータベース利用前提なので、共有したい情報をデータベースから読み込むModelを作って(Modelのコンストラクタで読み込んで、プロパティに保持するなどしておく)、全ControllerにそのModel利用を強制すればよい(AppControllerのuseプロパティにそのModel名を記載しておけばok)。

noname#244856
noname#244856
回答No.5

要は、接続のためのコストを取っ払ってしまいたいということですね。可能です。 【PDO使用時(参考)】 コンストラクタのオプションにて PDO::ATTR_PERSISTENT を True で渡します。 【CakePHP使用時】 情報が少し古いかもしれませんが、以下を参考にしてください。 http://www.phpbook.jp/cakephp/install/index2.html 但し、この接続の使いまわしはC言語で書かれたインタプリタレベルで行われることであり、PHPコードレベルで見れば隠蔽されている話です。よって、getInstanceにより必ず「スクリプト起動ごとに」1回目は新しいものが生成されることになります。これは言語仕様の問題なので気にするところではないでしょう。

bugz1977
質問者

お礼

情報のご提供ありがとうございます。

noname#244856
noname#244856
回答No.4

ちなみにこれだと全部Trueになってしまいます。 http://pastebin.com/Rz0NVd3a PHPのstaticなメソッドにおける初期化処理は親子別に行われるのに、staticなプロパティが親子間で共有されてしまう点は気持ち悪いと言えるかもしれませんね。他の言語の実装はどうなっているんでしょうかね。

bugz1977
質問者

お礼

情報提供ありがとうございます。 確かに気持ち悪いですね。 頂いたソースにログを出力してみたのですが、 public static function getInstance() { if (!static::$instance) { static::$instance = new static; LogError("インスタンス生成"); }else{ LogError("使い回し"); } return static::$instance; } リクエストの度に、インスタンスを新しく作ってしまうのですが、 私のイメージでは、システムを使用しているすべてのユーザで、インスタンスの情報を共有したいのですが、 何か書き方が違いますか? 1度作成したインスタンスは、Apacheを再起動するまでは、作成しないようにすることはCakePHPでは可能なのでしょうか。 Javaなら何度も実装したことがあるのですが、CakePHPでは初めて、かなり悩んでます。

noname#244856
noname#244856
回答No.3

getInstanceのシグネチャはこうですね。staticつけ忘れてました。こうしないとStrictStandardsエラーが発生してしまいます。(エラーを非表示にされているかもしれませんが) public static function getInstance() { ... } 以下のコードで期待した結果になります。 http://pastebin.com/gCqUEzs5

bugz1977
質問者

お礼

何度もありがとうございます。 ご教授頂いたソースを適用してみたのですが、すべてtrueで返却されます。

noname#244856
noname#244856
回答No.2

プロパティ使わなくてもstatic変数でいけますよ class Test {    private function __construct() { }    public function getInstance() {   static $self;   if (!$self) {     $self = new self;   }   return $self;  }   } 継承を前提にするなら class Test {    final protected function __construct() { }    public function getInstance() {   static $static;   if (!$static) {     $static = new static;   }   return $static;  }   }

bugz1977
質問者

お礼

ご教授ありがとうございます。 頂いたソースを真似して実行してみましたが、うまくいきませんでした。 何か事前設定などはありますでしょうか。

bugz1977
質問者

補足

CakePHPですが、2.Xを使用しております。

回答No.1

class Test{   public static $instance = null;   private function __construct(){}   public function getInstance(){    if(is_null(self::$instance)){     self::$instance = new static();    }    return self::$instance;   } }

参考URL:
http://ja.phptherightway.com/pages/Design-Patterns.html
bugz1977
質問者

お礼

ご教授ありがとうございます。 ご教授頂いたURLの内容をコピーして、実行してみましたが、 うまく実装出来ないようです。 呼出方などの問題ありますでしょうか。 ※ 補足のところで1つソースが間違っておりました。 public function beforeRender(){ $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); $obj2 = SingletonChild::getInstance(); var_dump($obj2 === Singleton::getInstance()); var_dump($obj2 === SingletonChild::getInstance()); } が正しいです。 var_dumpの結果が、全てtrueになってしまいます。

bugz1977
質問者

補足

参考URLで記載のソースを、Controller/Componentに配置し、AppControllerから呼び出しております。 App::uses('SingletonChild', 'Controller/Component'); App::uses('Singleton', 'Controller/Component'); 呼出方の問題でしょうか。 public function beforeRender(){ $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); $obj2 = Singleton::getInstance(); var_dump($obj2 === Singleton::getInstance()); var_dump($obj2 === SingletonChild::getInstance()); }

関連するQ&A

  • C++ シングルトン マルチスレッド

    標準C++でシングルトンを実装したいのですが。 class Singleton{ public: static Singleton* getInstance(){ if (_instance == NULL){ //スレッドAがこの時点で、スレッドBがNULLチェックすると破綻する _instance = new Singleton(); } return _instance; } private: Singleton(); static Singleton* _instance; }; マルチスレッドになると上記のパターンで破綻するといわれどうしたものかと考えております。 static Singleton* _instance = new Singleton(); と出来れば解決なのですが 「static const int データメンバ以外をクラス内で初期化することはできません」 とのことでそれもできず。 どのようにすればよいでしょうか。

  • シングルトン内で使用したオブジェクトのGC

    基本的な質問で恐縮ですがGCについて教えてください。 例えば、シングルトンインスタンス内のhogemethodメソッドにてHashMapのインスタンスを 生成・使用した場合(以下の質問に続く)、 【質問】 hogemethodメソッドが終わればHashMapのインスタンスはスコープを外れるので、hogeMap = null;などしなくてもGC対象となり、そのうちGCされるのでしょうか?いやいや、hogeMap = null; することによりGC対象となり、そのうちGCされるのでしょうか?それとも、nullセットしようがしまいが、シングルトンのインスタンスが存在し続ける限りGC対象とはなってもGCされることは無いのでしょうか? package hoge; public class MySingleton {  private static MySingleton instance = new MySingleton();  private MySingleton() {}  public static MySingleton getInstance() {   return instance;  }  public void hogemethod() {   HashMap hogeMap = new HashMap();   hogeMap .put("りんご", "apple");   hogeMap .put("ぶどう", "grapes");     :   hogeMap = null; ←★hogeMap をGC対象にするためにはnull代入は必要なのか?  } } よろしくお願いします。

    • ベストアンサー
    • Java
  • 同期について

    ちょっと疑問に思ったので質問させてください。 たとえばあるオブジェクトに対して同期(ここではinstance)する場合、ケース1とケース2では違いがありますでしょうか? ケース1: public static Test getInstance() {   synchronized(instance) { if(instance != null) { return instance; } else { instance = new Test(); return instance; } } ケース2: public static synchronized Test getInstance() { if(instance != null) { return instance; } else { instance = new Test(); return instance; } } 以上宜しくお願いします。

    • ベストアンサー
    • Java
  • &や&=について

    --------------------------------------- class TextSanitizer { function &getInstance() { static $instance; if (!isset($instance)) { $instance = new TextSanitizer(); } return $instance; } } $myts =& TextSanitizer::getInstance(); ------------------------------------------- 上記について3点質問がございます。 1.【&getInstance()】の&は何を意味していますでしょうか? 2.【$myts =& TextSanitizer::getInstance();】の&=は何を意味していますでしょうか? 3.getInstance()関数はどんなとき使用すべきでしょうか? ご検討がつく方アドバイスを宜しくお願いします。

    • ベストアンサー
    • PHP
  • PHP5でクラスを作成しています。

    PHP5でクラスを作成しています。 コンストラクタの段階で論理エラーにしたくて、インスタンス値をnullにしたいです。 つまり直ちにプログラムを止めずに、クラスの生成(インスタンス化)を失敗させる 方法を__construct()関数内でどのように書けば良いのでしょうか? class Sample { function __construct() { // この中で処理の異常が発生! // インスタンス作成を失敗させる or インスタンス値をヌルにする。 //? //?どのように書けば?? //? } } $a = new Sample(); if ($a === null) { printf("正しくインスタンスの生成ができませんでした。"); } よろしくお願いします。

    • 締切済み
    • PHP
  • Cakephp AppControllerについて

    CakePHPにて、 AppControllerクラスに処理を記述しようと思い、 app/app_controller.php を設置したのですが、 app/app_controller.php がどうしても呼び出されません。 色々調べてるのですが、どうしても原因が分かりません。 原因等分かる方がおりましたら教えて頂けますでしょうか? ---------------------- ■cakephpのバージョンは1.3です。 ■app/app_controller.phpの中身は↓です。 class AppController extends Controller { function __construct() { parent::__construct(); } function beforeFilter() { echo "test"; ←これが呼ばれない。 } } ----------------------

    • ベストアンサー
    • PHP
  • singletonパターン

    デザインパターンを勉強しているのですが、一つ気になっていることがあります。singletonパターンを使うとき、staticなメソッドgetInstance();で、唯一のインスタンスを得る場合、コードは Singleton obj1 = Singleton.getInstance(); となります。ここで疑問に思ったんですが、あるメソッドを使う場合、 instance名.method();という具合に記述されるんですが、この場合、 class名.method();となっています。メソッドを使うときって、class名.method();でも大丈夫なんですか?質問文がわかりにくいかもしれませんがどうぞよろしくお願いします。

    • ベストアンサー
    • Java
  • singletonによるインターフェイスの実装

    Java勉強中の初心者です。 標題の件についてお願いします。 以下、簡単に条件を説明させていただきます。 Aクラス = メインクラス Bクラス = インターフェイスクラス Cクラス = DとEを動的に生成するクラス Dクラス = インターフェイスを実装するクラス Eクラス = インターフェイスを実装するクラス AクラスにB.getInstance(name)があります。 for文の無限ループがあります。 Cクラス class C { public static B getInstance(String name) { // Aクラスのaと変数nameが比較して一致したら // Dクラスのインスタンス生成 // 一致しなかったらEクラスのインスタンス生成 if(A.a.equals(name)){ return D.getInstance(); }else{ return E.getInstance(); } } } Dクラス class D implements B{ private D() { } public static D getInstance() { D d = new D(); return d; } // インターフェイスでのメソッド省略します。 } Eクラス class E implements B{ private E() { } public static E getInstance() { E e = new E(); return e; } // インターフェイスでのメソッド省略します。 } この条件の時にnewするたびにインスタンスが 生成されてしまいます。 インスタンスの生成が一度だけしか 生成されないようにするには、C,D,Eクラスで どのように記述すればいいか悩んでいます。 (骨組みは書けましたが) クラスを簡単に省略してわかりづらいと 思いますがよろしくお願いします。

    • ベストアンサー
    • Java
  • PHP T_STRINGエラー?

    新しくPHPのサイトを作成しようとしたんですが、 syntax error, unexpected '{', expecting T_STRING in と表示されてどうにも使用がありません。 どこが原因でエラーが出てるのでしょうか? エラー行は7行と表示されていますが、いまいちわかりません スクリプトは以下の記述の通りです <?php require './Request.php'; require './Cookie.php'; final class SystemMain extends { private static $instance; private $modeName; public static function getInstance() { if (self::$instance === null) { self::$instance = new SytemMain(); } return self::$instance; } public function setMode() { if (file_exists('./maintenance')) { $this->modeName = 'Maintenance'; } else { $str = Request::both('mode'); if (!$str) { $this->modeName = 'Top'; } else if (file_exists('./script/mode/' . $str . '.php')) { $this->modeName = $str; } else { $this->modeName = 'NotFound'; } } require_once './script/mode/' . $this->modeName . '.php'; } public function getMode() { return $this->modeName; } } ?> Request.php <? class Request extends { public static function get($str) { return isset($_GET[$str]) ? $_GET[$str] : null; } public static function post($str) { return isset($_POST[$str]) ? $_POST[$str] : null; } public static function both($str) { $post = self::post($str); return $post ? $post : self::get($str); } } ?> Cookie.php <? class Cookie extends { public static function set($name, $value, $expire = 0) { return setcookie($name, $value, $expire); } public static function get($str) { return isset($_COOKIE[$str]) ? $_COOKIE[$str] : null; } public static function clear($str) { $_COOKIE[$str] = ""; return setcookie($str, ""); } } ?>

    • ベストアンサー
    • PHP
  • Cakephp2.0で、PhantomJs

    Cakephp 2.0のConsole/Commandで、スクレイピングを行う処理を実装しようとしています。 PhantomJsを使おうとしていますがどうもうまくいきません。 composerを利用してPhantomJsを、 /XAMPP/xamppfiles/htdocs/cakephp/app/Vendor にインストールしました。 ”/XAMPP/xamppfiles/htdocs/cakephp/app/” に test.phpとして、 <?PHP require_once('vendor/autoload.php' ); use JonnyW\PhantomJs\Client; $client = Client::getInstance(); $client->getEngine()->setPath('vendor/bin/phantomjs'); $request = $client->getMessageFactory()->createRequest(); $response = $client->getMessageFactory()->createResponse(); $request->setMethod('GET'); $request->setUrl('https://pg.kdtk.net/sample/phamtomjs_test.html'); $client->send($request, $response); echo "request url: " . $request->getUrl() . "\n"; echo "response: " . $response->getStatus() . "\n"; if($response->getStatus() === 200) { echo "content: \n"; echo $response->getContent(); } ?> というサンプルプログラムを実行するとうまくいきました。 これを、Console/Commandで実装したいのですが、どのように実装したら良いかわかりません。 例えば /XAMPP/xamppfiles/htdocs/cakephp/app/Console/Command に、 SampleShell.php として保存し、 <?php class SampleShell extends AppShell { public function startup() { parent::startup(); App::import('Vendor', 'Client', array('file' => 'JonnyW/PhantomJs/Client.php')); } // メイン実行関数 public function main() { $client = Client::getInstance(); } } ?> php cake.php Sample を実装すると、 PHP Fatal error: Class 'Client' not found ・・・ とエラーとなります。 インスタンスを生成できるようにするにはどのようにすれば良いのでしょうか? ご教示いただきますよう、何卒宜しくお願い申し上げます。

    • 締切済み
    • PHP

専門家に質問してみよう