通过DI容器获取Zend_Session_Namespace的实例

时间:2011-04-22 13:28:09

标签: php dependency-injection anonymous-function

我想在模型中检索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内部服务器错误:(

1 个答案:

答案 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