【问题标题】:Problems with redeclaring classes when using PHP's class_alias in a functional test在功能测试中使用 PHP 的 class_alias 时重新声明类的问题
【发布时间】:2010-08-03 10:40:34
【问题描述】:

我正在使用 PHP 5.3 的 class_alias 来帮助处理我的 Symfony 1.4 (Doctrine) 表单。我使用单个操作来处​​理多个表单页面,但使用 switch 语句来选择要使用的表单类。

public function executeEdit(sfWebRequest $request) {
  switch($request->getParameter('page')) {
    case 'page-1':
      class_alias('MyFormPage1Form', 'FormAlias');
    break;
    ...
  }
  $this->form = new FormAlias($obj);
}

这在浏览网站时效果很好,但我的功能测试失败了,因为当一个页面被多次加载时,就像这样:

$browser->info('1 - Edit Form Page 1')->

  get('/myforms/edit')->
  with('response')->begin()->
    isStatusCode(200)->
  end()->

  get('/myforms/edit')->
  with('response')->begin()->
    isStatusCode(200)->
  end();

我收到了对第二个请求的 500 响应,并出现以下错误:

最后一个请求引发了未捕获的异常 RuntimeException: PHP 在 /.../apps/frontend/modules/.../actions/actions.class.php 第 225 行发送了警告错误(无法重新声明类 FormAlias)

这使得测试表单提交(通常回发给自己)变得非常困难。

这大概是因为 Symfony 的测试人员没有以同样的方式清除吞吐量。 有没有办法“取消别名”或以其他方式允许这种重新声明?

【问题讨论】:

    标签: php symfony1 functional-testing


    【解决方案1】:

    作为替代解决方案,您可以将要实例化的类的名称分配给一个变量并新建:

    public function executeEdit(sfWebRequest $request) {
      $formType;
      switch($request->getParameter('page')) {
        case 'page-1':
          $formType = 'MyFormPage1Form';
        break;
        ...
      }
      $this->form = new $formType();
    }
    

    这不使用 class_alias,而是将实例化保持在一个位置。

    【讨论】:

    • 整洁。不知道这是可能的。似乎使 class_alias 有点多余。我认为存在性能差异。
    • class_alias 必须保留别名类的记录,这引入了一个局部变量。不知道哪个影响更大。 class_alias 一定是出于某种原因添加到 5.3.0 中的,但我想不出一个。
    【解决方案2】:

    我不确定这是否可能,但从手册来看,我会说不。一旦类被别名,就无法重置它或用不同的名称重新声明它。但是话又说回来,为什么要使用别名呢?

    根据您的代码,我假设您在每个额外的 case 块中进行别名处理。但如果是这样,您也可以简单地在这些块中实例化表单,例如

    public function executeEdit(sfWebRequest $request) {
      switch($request->getParameter('page')) {
        case 'page-1':
          $form = new MyFormPage1Form($obj);
        break;
        ...
      }
      $this->form = $form;
    }
    

    在使用class_alias 时,无论如何您都将类名硬编码到 switch/case 块中。使用它没有任何优势。如果你想动态地做,你可以创建一个从'page'到'className'的数组映射,然后简单地查找适当的类。

    public function executeEdit(sfWebRequest $request) {
      $mapping = array(
          'page-1' => 'MyFormPage1Form',
          // more mappings
      );
      $form = NULL;
      $id = $request->getParameter('page');
      if(array_key_exists($id, $mapping)) {
           $className = $mapping[$id];
           $form = new $className($obj);
      }
      $this->form = $form;
    }
    

    这样,您还可以将整个映射放在一个配置文件中。或者您可以创建 FormFactory。

    public function executeEdit(sfWebRequest $request) {
        $this->form = FormFactory::create($request->getParameter('page'), $obj);
    }
    

    如果你使用Symfony Components DI Container,你也可以摆脱硬编码的工厂依赖,只使用服务容器来获取表单。这将是 IMO 最干净的方法。基本上,在我这里使用class_alias 感觉不合适。

    【讨论】:

    • 我没有在示例中展示的函数更复杂,这使得别名比看起来更有用。但是,可以肯定的是,映射看起来是一种更好的处理方式。
    【解决方案3】:
    function class_alias_once($class, $alias) {
        if (!class_exists($alias)) {
            class_alias($class, $alias);
        }
    }
    

    这并不能解决问题本身,但通过使用此功能可以确保您不会收到错误消息。也许这足以满足您的目的。

    【讨论】:

    • 杰普,你是完全正确的。 parsekit 和 classkit 都没有这样的方法。从我的答案中删除了那部分。
    猜你喜欢
    • 1970-01-01
    • 2013-10-04
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-29
    • 2021-05-31
    • 1970-01-01
    相关资源
    最近更新 更多