通过 DI 容器获取 Zend_Session_Namespace 的实例

发布于 2024-11-03 04:19:26 字数 3824 浏览 3 评论 0原文

我想在我的模型中检索 Zend_Session_Namespace 的实例,但我不希望他们对 Zend 的实现有具体的依赖(所以我可以模拟它进行测试)。

会话实例需要在调用时传递给它一些配置。我的其他依赖项没有,并且可以在引导过程中进行配置。

我有一个非常基本的 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 内部服务器错误:(

I want to retrieve an instance of Zend_Session_Namespace within my models but I don't want them to have a concrete dependency on Zend's implementation (so I can mock it for it testing).

The session instance needs some configuration passed to it at call time. My other dependencies do not and can be configured during the bootstap process.

I have a very basic DI container, borrowed from 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];
  }

}

I'm using this to wire up my dependencies:

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

I'm using these dependencies within my base model (I don't want my model to know so much about my container configuration):

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];
  }

}

This enables my subclasses to retrieve a session instance reasonably conveniently:

class Model_User extends Lib_Model {

  protected $_sessionName = 'user';

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

}

Or by passing the session namespace as an argument:

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

However, my Lib_Model::getSession() method is more complex than I would like, and knows too much about my DI container. Ideally want to obtain an instance of Zend_Session_Namespace by calling:

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];
  }

}

I appreciate my DI container is checking if it's services are callable (e.g. anonymous functions) and executing them. If I remove this behaviour the auto-wiring element will crumble?

Any ideas how I can achieve $container->session('my_namespace') to return the equivalent of new Zend_Session_Namespace('my_namespace')?


Update: I thought I was on to something by changing the configuration of my container:

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

So that $container->session would return a function. Updating my Lib_Model class:

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];
  }

}

Unfortunately this gives me a 500 internal server error :(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

难得心□动 2024-11-10 04:19:26

我通过稍微调整 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

I resolved the 500 internal server error by adjusting Lib_Model::getSession() slightly:

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];
}

I put together a simple script slowly building up it's complexity until it dawned on me I was calling an undefined method on Lib_Model, though no error message was displayed by PHP running under apache.

$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");

Test output:

$ 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文