我想在模型中检索Zend_Session_Namespace的实例,但我不希望它们对Zend的实现有一个具体的依赖(因此我可以模拟它进行测试)。
会话实例需要在调用时传递给它的一些配置。我的其他依赖项没有,可以在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内部服务器错误:(
答案 0 :(得分: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