2

情况

在我正在构建的这个网络应用程序中,有一个“引导”序列,它定义(通过常量)并启动一个扩展控制器。目前,控制器通过一系列静态变量跟踪将在后期渲染阶段部署的资产(脚本文件、css 等)。我将在这里简化代码,将其视为伪 PHP。

/* CONTROLLER CLASS */
class Controller {
    protected static $aryScriptFiles = array();
    public function __construct() {
        /* Behaviour */
        /* Some logic that identifies/calls Home_Controller method Index */
    }
    public static function Add_Script($strFileName) {
        static::$aryScriptFiles[] = $strFileName;
    }    
}

/* HOME_CONTROLLER CLASS */
class Home_Controller extends Controller {
    protected static $aryScriptFiles = array('default', 'carousel', 'etc');
    protected function Index() {
        /* Behaviour */
        /* Load the view as an include. It is "part" of the User_Controller */ 
    }
}

/* EXAMPLE_HELPER */
class Example_Helper {
    public static function Test() {

         /* THE NEXT LINE IS IMPORTANT FOR THE QUESTION */
         $objController = CONTROLLER;
         $objController::Add_Script('dominoes');
    }    
}

/* INDEX VIEW FILE */
<h1>Welcome!</h1>
<?php
echo get_class(); <-- Would echo 'User_Controller'
Example_Helper::Test();

/* Simplification of render process */
foreach(static::$aryScriptFiles as $strFileName) {
    /* Render the HTML script tag */
}
?>

流动

好的,鉴于上述情况,有一个引导程序最终会调用 User_Controller。例如,我只是简单地定义了它们,让您知道脚本将遵循什么状态。

$strControllerName = 'User_Controller';
define('CONTROLLER', $strControllerName);
$objController = new $strControllerName();

你最终得到的是具有 4 个条目的aryScriptFiles数组,这很好用。

问题

在继续阅读之前,请注意我不想使用魔法方法、全局变量或必须将控制器名称的引用传递给 Helper 函数。

我想尝试删除帮助文件中将当前控制器名称从常量中提取到变量的行。

$objController = CONTROLLER; <-- I want this to shoo shoo

如果我只是尝试使用以下内容,则通过 Helper 添加的脚本文件是原始Controller 数组的一部分,而不是 Home 控制器。

Controller::Add_Script('dominoes'); <-- Will not be part of the Home_Controller array

问题

请我从 SO 社区获得一些意见,您认为解决此问题的最佳方法是考虑到控制器名称会有所不同吗?我在这个练习中的主要目标是:

  • 保持视图文件非常简单
  • 保持 Helper 文件简单。
  • 避免向 Home_Controller 添加任何不必要的代码

我目前认为最好的选择之一是将“资产”托管在一个单独的班级中,只是想知道这是否可能。

谢谢阅读。

4

2 回答 2

2

首先,考虑一下您的关注点分离。管理资产真的应该是控制者的责任吗?. 你为什么首先将添加资产的方法设为静态?

我不想使用魔术方法、全局变量或必须将控制器名称的引用传递给 Helper 函数。

你在期待什么?如果您试图强制一个类依赖于完全不同范围和上下文中的另一个类,您唯一的选择是使用丑陋的 hack 来使您的对象全局可访问。

依赖注入救援

为什么你的助手应该知道控制器是什么以及控制器是如何从外部处理的?

您的助手唯一应该做的就是使用控制器(在您的情况下)。它不应该尝试神奇地检测正在使用的控制器。它应该只需要一个控制器并使用它进行操作。

class Example_Helper {
    public static function Test($controller) {
         $controller::Add_Script('dominoes');
    }    
}

Example_Helper::Test($objController);

由于addScript()方法和$aryScriptFiles属性无论如何都是静态的,因此您也可以只在父控制器的帮助程序中调用该方法。这没什么区别。

另外,您为什么要从视图中与您的控制器交谈?视图应该是“哑”的,它不应该能够保存和操作数据,除了那些由控制器传递给它的数据。

将功能添加到您的控制器或将所需资产传递给您的视图的服务之一,而不是强制视图自己从控制器获取数据,这不是更有意义吗?

我认为您的代码中存在一些逻辑缺陷。特别是您对静态属性和方法的使用。如果你能澄清一点,我可以详细一点。

于 2014-07-09T09:51:43.477 回答
0

除了架构问题(资产确实应该由单独AssetManager的. 这使您可以编写如下代码:get_called_class

$assets = [];  // Global for brevity of example

class Base {
  static function addScript($script)
  {
    global $assets;

    $myName = get_called_class();
    $assets[$myName][] = $script;
  }
}

class Derived extends Base {
  public function __construct()
  {
    self::addScript('test');
  }
}

$foo = new Derived();
var_dump($assets);

然后将输出以下内容

array(1) {
  ["Derived"]=>
  array(1) {
    [0]=>
    string(4) "test"
  }
}

请注意,使用get_class而不是在get_called_class这里将数组的名称显示为Base而不是Derived,而Derived这是您需要的。通过这种方式,您可以在 中嵌入辅助函数Controller,它会自动派生类名并将其转发给中央资产管理器。

于 2014-07-09T09:59:58.093 回答