Вот так
Создайте загрузку имени класса, в которой есть метод с именем helper, если вы хотите, чтобы он был доступен с помощью $ syslog_helper, тогда load должна иметь возможность вызывать исходный класс, поэтому при созданииэкземпляр передает $ this как часть своего конструктора.Тогда основной класс должен использовать магический метод __set и т. Д.
Вспомогательный класс для загрузки:
class syslog_helper{
}
Класс загрузчика:
class loader{
protected $obj;
public function __construct($obj){
//save the controller instance as a property
$this->obj = $obj;
}
public function helper($class){
//require the class file - don't need to in this case as they are all in the same file for sandbox
//require_once HELPER_DIR.$class.'.php';
//create a new instance of Helper and assign it back to the controller
$this->obj->$class = new $class;
}
}
Базовый класс контроллера
class foo{
public $data = [];
public $load;
public function __construct(){
//create the loader instance, pass an instance of the controller (this)
$this->load = new loader($this);
}
public function bar(){
//call the loader's helper() method with the name of the helper class
$this->load->helper('syslog_helper');
print_r($this->syslog_helper);
}
public function __set($key, $value){
//create a dynamic property
$this->data[$key] = $value;
}
public function __get($key){
//get a dynamic property
return $this->data[$key];
}
}
Позвоните:
(new foo)->bar();
Вывод:
syslog_helper Object
(
)
Песочница
Как вы можете видеть выше,$this->syslog_helper
заполняется нашим вспомогательным классом так же, как это делает CI.
Таким образом, он работает в следующем порядке:
- $ foo = new foo - createэкземпляр контроллера, назначьте класс загрузчика (с обратной ссылкой на контроллер)
$this->load = new loader($this);
- $ foo-> bar () - вызовите
bar()
это будет функция запросав контроллере, например, к чему ведет URL. - $ foo-> load-> helper ('syslog_helper') - используйте свойство
load
(экземпляр загрузчика) длявызовите его вспомогательный метод, передав имя вспомогательного класса в виде строки.Вспомогательный метод должен требовать файл класса, а затем создать экземпляр этого класса.new $class
- $ this-> obj -> $ class = new $ class; - тогда этот экземпляр присваивается динамическому свойству, названному так же, как было передано в
- $ this-> obj -> $ class - Волшебный метод __set контроллера запускается, сохраняя экземпляр помощника в
Controler->data[$helper]
- $ foo-> syslog_helper () - Волшебный метод контроллера __get срабатывает, возвращая
Controler->data[$helper]
или экземпляр только что созданного помощника.
Я только что это придумал, но я уверен, что CI похож.Вы можете посмотреть в родительском классе контроллеров и т. Д. И посмотреть, как они это делают.
Надеюсь, что это имеет смысл ...
Одно простое улучшение вы могли бысделать для кода выше
Я думаю, что CI делает это, чтобы разрешить псевдоним свойства ... вот так:
class loader{
protected $obj;
public function __construct($obj){
//save the controller instance as a property
$this->obj = $obj;
}
public function helper($class, $alias = null){
//if no alias default to the class name
if(!$alias) $alias = $class;
//require the class file - don't need to in this case as they are all in the same file for sandbox
//require_once APPPATH.'helpers/'.$class.'.php';
//create a new instance of Helper and assign it back to the controller
$this->obj->$alias = new $class;
}
}
Теперь, если мы сделали это в методе bar контроллера:
class foo{
public function bar(){
//call the loader's helper() method with the name of the helper class
$this->load->helper('syslog_helper');
print_r($this->syslog_helper);
$this->load->helper('syslog_helper', 'syslog_helper_2');
print_r($this->syslog_helper_2);
}
Вывод:
syslog_helper Object
(
)
syslog_helper Object
(
)
Теперь у вас есть 2 экземпляра помощника, один с именем syslog_helper
, а другой syslog_helper_2
.Если бы мы не называли их псевдонимами, второй вызов просто переписал бы свойство в контроллере, оставив нам только один экземпляр.
Итак, как вы можете видеть выше, мы добавили большую гибкость, по сути, с одной строкой кода.Большие улучшения не обязательно должны быть сложными.
Sandboxy
Очевидно, вы должны это немного конкретизировать.Добавляя больше вещей, таких как проверка ошибок для классов (файлов), которые не существуют, __unset
и __isset
магические методы и т.д. ... Но это базовая функциональность, которую вы хотели.
Точно так же вы можете добавить методы model
и library
, с единственной реальной разницей - местоположением.Для этого я бы, вероятно, использовал магический метод __call
вместо 3 функций, которые делают то же самое.
Реализация load-> model, load-> library и load-> helper
class loader{
protected $obj;
public function __construct($obj){
//save the controller instance as a property
$this->obj = $obj;
}
public function __call($method, $args){
//type => folder
$allowed = ['helper'=>'helpers','model'=>'models', 'library'=>'libraries'];
if(!isset($allowed[$method])) throw new Exception('Unknown method '.$method);
if(!isset($args[0])) throw new Exception('Missing required argument for method '.$method);
$class = $args[0];
$alias = isset($args[1]) ? $args[1] : $class;
//require the class file - don't need to in this case as they are all in the same file for sandbox
//require_once APPPATH.$allowed[$method].'/'.$class.'.php';
//create a new instance of Helper and assign it back to the controller
$this->obj->$alias = new $class;
}
}
Песочница
Реализация синглетонов
Синглтон в основном повторно использует тот же экземпляр класса для будущеговызовы, вы можете реализовать это с помощью нескольких изменений в загрузчике:
class syslog_helper{
public $test;
}
class loader{
protected $obj;
protected static $instances = [];
public function __construct($obj){
$this->obj = $obj;
}
public function __call($method, $args){
//type => folder
$allowed = ['helper'=>'helpers','model'=>'models', 'library'=>'libraries'];
if(!isset($allowed[$method])) throw new Exception('Unknown method '.$method);
if(!isset($args[0])) throw new Exception('Missing required argument for method '.$method);
$class = $args[0];
$alias = isset($args[1]) ? $args[1] : $class;
//if this is the first time we instantiated [$method][$alias] save it
if(!isset(static::$instances[$method][$alias])){
//require the class file - don't need to in this case as they are all in the same file for sandbox
//require_once APPPATH.$allowed[$method].'/'.$class.'.php';
//create a new instance of Helper and assign it back to the controller
static::$instances[$method][$alias] = new $class;
}
//return the saved static instance
$this->obj->$alias = static::$instances[$method][$alias];
}
}
class foo{
public $data = [];
public $load;
public function __construct(){
$this->load = new loader($this);
}
public function bar(){
$this->load->helper('syslog_helper');
print_r('bar::Test before: '.$this->syslog_helper->test."\n");
$this->syslog_helper->test = 'test';
print_r('bar:Test after: '.$this->syslog_helper->test."\n");
}
public function biz(){
$this->load->helper('syslog_helper');
print_r('biz:Test: '.$this->syslog_helper->test."\n");
}
public function __set($key, $value){
$this->data[$key] = $value;
}
public function __get($key){
return $this->data[$key];
}
}
$foo = new foo;
$foo->bar();
$foo->biz();
Вывод:
bar::Test before:
bar:Test after: test
biz:Test: test
Песочница
Важная вещьздесь, когда мы вызываем $this->load->helper('syslog_helper');
из biz()
в контроллере, мы получаем тот же экземпляр помощника, который мы создали ранее.Вы можете сказать это, потому что открытое свойство, которое я добавил помощнику, сохраняет значение, которое мы установили в bar()
.На самом деле вы могли бы вызывать это где угодно в вашем коде и получать тот же экземпляр с теми же данными, хранящимися в нем, для примеров было просто (короче) сделать это таким образом.
Это полезно, если вам нужен один и тот же помощник в нескольких классах, вместо того, чтобы создавать несколько экземпляров, вы можете использовать их повторно. Я не уверен, что CI делает это прямо с моей головы ... LOL
В этом случае я думаю, что допустимо делать их как одиночные, если вам нужна новая копия, вы можете просто создать псевдоним, и тогда это будет независимый экземпляр.
Последнее, что я должен добавить, это то, что CI, вероятно, не передает экземпляр контроллера в класс загрузчика. Это связано с тем, что CI вызывает контроллер из маршрутизации, поэтому у него уже есть экземпляр Controller. А поскольку CI является одноэлементным, к нему, вероятно, можно получить доступ с помощью $CI = get_instance();
внутри загрузчика, поэтому нет необходимости передавать его так, как я показал в рамках CI. По сути, они просто получают доступ к одним и тем же данным по-разному.
Ура!