2011-04-22 106 views
1

我想在我的模型中檢索Zend_Session_Namespace的實例,但我不希望它們對Zend的實現有一個具體的依賴關係(所以我可以對它進行測試)。通過DI容器獲取Zend_Session_Namespace的實例

會話實例需要在通話時傳遞給它的一些配置。我的其他依賴關係不可以在bootstap進程中配置。

我有一個非常基本的DI容器,從Fabien Potencier借:

class Lib_Container { 

    protected $services = array(); 

    function __set($id, $service) { 
    $this->services[$id] = $service; 
    } 

    function __get($id) { 
    if (!isset($this->services[$id])) { 
     throw new ServiceNotRegisteredException(
     "Service '$id' has not been registered" 
    ); 
    } 

    if (is_callable($this->services[$id])) { 
     return $this->services[$id]($this); 
    } 

    return $this->services[$id]; 
    } 

} 

我使用這個要連接我的依賴關係:

$container = new Lib_Container; 
$container->session = function($c) { 
    return new Zend_Session_Namespace($c->sessionName); 
}; 
... 

我用我的基地內,這些依賴模型(我不希望我的模型對我的容器配置瞭解太多):

class Lib_Model { 

    protected $_container; 
    protected $_sessionName = 'default'; 
    protected $_sessionInstance; 

    public function __construct($container) { 
    $this->_container = $container; 
    } 

    public function getDB() { 
    return $this->_container->database; 
    } 

    public function getRequest() { 
    return $this->_container->request; 
    } 

    public function getSession($ns = null) { 
    $ns = ($ns == null) ? $this->_sessionName : $ns; 
    if (!isset($this->_sessionInstance[$ns])) { 
     $this->_container->sessionName = $ns; 
     $this->_sessionInstance[$ns] = $this->_container->session; 
    } 
    return $this->_sessionInstance[$ns]; 
    } 

} 

這使我的子類,以獲取合理方便的一個會話實例:

class Model_User extends Lib_Model { 

    protected $_sessionName = 'user'; 

    public function loggedIn() { 
    $session = $this->getSession(); 
    return ($session && $session->loggedIn) ? true : false; 
    } 

} 

或傳遞會話命名空間作爲參數:

$session = $this->getSession('admin'); 

但是,我Lib_Model::getSession()方法相當複雜,我想,並且知道我的DI容器太多。理想的情況是想通過調用獲得的Zend_Session_Namespace一個實例:

class Lib_Model { 

    protected $_sessionName = 'default'; 
    protected $_sessionFactory; 
    ... 

    public function __construct($container) { 
    $this->_sessionFactory = $container->session; 
    } 

    ... 

    public function getSession($ns = null) { 
    $ns = ($ns == null) ? $this->_sessionName : $ns; 
    if (!isset($this->_sessionInstance[$ns])) { 
     $this->_sessionInstance[$ns] = $this->_sessionFactory($ns); 
    } 
    return $this->_sessionInstance[$ns]; 
    } 

} 

我很感激,如果它的服務調用(如匿名函數)我的DI容器,檢查和執行它們。如果我消除這種行爲,自動佈線元件會崩潰?

任何想法如何才能實現$container->session('my_namespace')返回相當於new Zend_Session_Namespace('my_namespace')


更新:我以爲我到的東西改變我的容器的配置:

$container->session = function($c) { 
    $s = function($namespace) { 
    return new Zend_Session_Namespace($namespace); 
    }; 
    return $s; 
}; 

這樣$container->session將返回的功能。更新我的Lib_Model類:

Lib_Model { 

    private $_sessionFactory; 
    ... 

    public function __construct($container) { 
    ... 
    $this->_sessionFactory = $container->session; 
    } 

    ... 

    public function getSession($ns = null) { 
    $ns = ($ns == null) ? $this->_sessionName : $ns; 
    if (!isset($this->_sessionInstance[$ns])) 
     $this->_sessionInstance[$ns] = $this->_sessionFactory($ns); 
    return $this->_sessionInstance[$ns]; 
    } 

} 

不幸的是這給了我一個500內部服務器錯誤:(

回答

1

我通過調整Lib_Model::getSession()稍微解決了500內部服務器錯誤:

public function getSession($ns = null) { 
    $ns = ($ns == null) ? $this->_sessionName : $ns; 
    if (!isset($this->_sessionInstance[$ns])) { 
    $sessionFactory = $this->_session; 
    $this->_sessionInstance[$ns] = $sessionFactory($ns); 
    } 
    return $this->_sessionInstance[$ns]; 
} 

我放在一起簡單的腳本慢慢建立它的複雜性,直到它曙光我在Lib_Model我調用了一個未定義的方法,雖然沒有錯誤信息顯示在Apache下運行的PHP。

$f = function() { 
    return function($name) { 
    echo "Hello " . $name . PHP_EOL; 
    }; 
}; 

$hello = $f(); 
$hello("World"); 
unset($hello); 

// second test 

class Container { 

    protected $services = array(); 

    function __set($id, $service) { 
    $this->services[$id] = $service; 
    } 

    function __get($id) { 
    if (!isset($this->services[$id])) { 
     throw new ServiceNotRegisteredException(
     "Service '$id' has not been registered" 
    ); 
    } 

    if (is_callable($this->services[$id])) { 
     return $this->services[$id]($this); 
    } 

    return $this->services[$id]; 
    } 
} 

$c = new Container; 
$c->h = function() { 
    return function($name) { 
    echo "Hello " . $name . PHP_EOL; 
    }; 
}; 

$hello = $c->h; 
$hello("Bert"); 

// third test 

class MyTest { 
    public $attr; 
} 

$test = new MyTest; 
$test->attr = $c->h; 
$test->attr("Ernie"); 

測試輸出:

$ php -f test.php 
Hello World 
Hello Bert 
PHP Fatal error: Call to undefined method MyTest::attr() in /home/greg/test.php on line 53