模型的方法中支持实时加载其它模型并且立即调用,又一强大特性。
VgotFaster 和 CI 因为单例模式围绕着一个控制器的实例进行的,导致模型中要使用 $this->load 等类库实例需要用额外的方法去弥补,Model 里的 _assignLibraries() 方法便是实现将所有已加载的类库再赋给自己的作用。
而这些特性导致在模型的具体方法中调用 $this->load->model('someModel'); 的时候,不能立即通过 $this->someModel->bar() 去调用刚加载的模型的方法,因为 _assignLibraries() 只能将所有的类库加载到正在加载的模型中,而无法负责将自己注入进加载自己的模型中,只能通过先在另一个方法里加载,比如构造函数,然后才能通过 $this 调用,或者使用 getInstance() 获得控制器实例后从控制器实例中加载。
现在 VgotFaster 使用注入广播的形式弥补了这个缺陷,在模型的方法中,你可以直接加载另一个模型并调用其中的方法。
如:
<?php class DemoModel extends \Model { public function foo() { $this->load->model('someModel'); $this->someModel->bar(); //在同一个方法中加载模型,可以立即调用了。 } }
这里为什么不在 _assignLibraries() 中直接实现 _injectBroadcase() 的功能,而要另建一个方法呢?
因为我们希望在加载的模型的构造函数中可以直接使用 $this->load 等方法,所以 _assignLibraries() 是在正在加载的模型的构造函数中调用的,这样在用户建立的模型的构造函数中可以直接调用已加载的类库。
<?php class DemoModel extends \Model { public function __construct() { parent::__construct(); //自己实现的构造函数必须实现父类的构造函数 $this->load->library(..); //可以直接使用 $this->load 等 $this->config->get(..) }
因加载模型支持更名,所以模型实例化时自己并不知道自己在控制器中是以什么样的属性名称存在在,如果要实现就必须在实例化时将模型在控制器中的属性名称传递给加载的模型,比如存在另一个变量中,或者在构造函数中传递。
如果在构造函数中传递,一旦用户建立的模型中自己写了构造函数,那么构造函数也必须有该参数并且传递给父类的构造函数,这就破坏了建立模型的方便性,优雅性,包括其它方法,会使得框架中的应用层被核心层污染,开发者不再能只关心自己的业务逻辑了,需要关心框架本身的问题(模型的构造函数中需要调用父类的构造函数已经是底线)。
所以为了避免这些,使用另一个方法,向其传递它在控制器中的实例名称,是更好的办法。
Loader.php injectModel:
/** * 由 model() 方法调用,载入模型 * * @param mixed $name * @param string $instance Set another instance name * @return Object */ protected function injectModel($name, $instance='') { $file = APPLICATION_PATH.'/models/'.$name.'.php'; $lsp = strrpos($name, '/'); //Last Slash Point $lsp !== false && $name = substr($name, $lsp+1); $instance = $instance == '' ? $name : $instance; _systemLog("Try to load model '$name' as '$instance'"); $VF =& getInstance(); $baseProps = get_object_vars($VF); if (!isset($baseProps[$instance]) || empty($VF->$instance)) { $lsp = strrpos($file, '/'); is_file($file) ? include_once $file : showError('No Found Model File: '.substr($file, $lsp+1)); _systemLog("Load model '$name' instance '$instance'"); $class = '\\Model\\'.ucfirst($name); $VF->$instance = new $class; $VF->$instance->_injectBroadcast($instance); $this->models[] = $instance; //记录到已载入的模型列表中 } return $VF->$instance; }
Interface.php
//Inject this model to other loaded models public function _injectBroadcast($instance) { $VF =& getInstance(); foreach (array_keys(get_object_vars($VF)) as $key) { if (is_object($VF->$key) AND ($VF->$key instanceof Model) AND !($VF->$key instanceof $this->_selfClassName) && !isset($VF->$key->$instance)) { $VF->$key->$instance =& $this; } } }
评论 共有 0 条评论
暂无评论,快发表你的评论吧。