PHP后期静态绑定引用

时间:2014-07-09 09:26:42

标签: php object simplify maintainability late-static-binding

情况

在我正在构建的这个网络应用程序中,有一个" bootstrap"定义(通过常量)并启动扩展控制器的序列。目前,控制器通过一系列静态变量跟踪将在后面的渲染阶段部署的资产(脚本文件,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添加任何超出必要的代码

我目前认为最好的选择之一就是主持资产&#34;在一个单独的课程中,只想知道是否可能。

感谢阅读。

2 个答案:

答案 0 :(得分:2)

首先,考虑一下你所关注的问题。 管理员是否真的应该负责管理资产?。你为什么首先使用静态添加资产的方法?

  

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

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

Dependency Injection救援

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

你的助手应该做的唯一事情是使用控制器(在你的情况下)。它不应该试图神奇地检测正在使用的控制器。它应该只需要一个控制器并使用它。

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

Example_Helper::Test($objController);

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

另外,为什么你想从视图中与你的控制器交谈?观点应该是“愚蠢的”#34;除了控制器传递给它的数据外,它不应该能够保存和操作数据。

向控制器或其中一项将所需资源传递到您的视图的服务添加功能更有意义,而不是强制视图从中获取数据来自控制器本身?

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

答案 1 :(得分:0)

除了架构问题(资产确实应该由单独的AssetManager管理),因为PHP相当特殊的自己的架构,你的问题可以相对容易地解决,特别是暴露通过像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);

哪个will then output the following

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

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