Создайте собственную функцию loadhelper (как в CodeIgniter) - PullRequest
0 голосов
/ 22 июня 2019

Я стараюсь каждый день делать что-то новое.Теперь я хочу сделать функцию динамической загрузки помощника без включения и создания нового объекта класса

В коде воспламенителя, который выглядит как $this->load->helper('syslog_helper');

, и теперь мы можем использовать syslog_helper->some_function() файл автоматически, включая, объект создается автоматически, и мы можем использовать его

Вопрос: как мне сделать то же самое, используя чистый PHP?

1 Ответ

3 голосов
/ 22 июня 2019

Вот так

Создайте загрузку имени класса, в которой есть метод с именем 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.

Таким образом, он работает в следующем порядке:

  1. $ foo = new foo - createэкземпляр контроллера, назначьте класс загрузчика (с обратной ссылкой на контроллер) $this->load = new loader($this);
  2. $ foo-> bar () - вызовите bar() это будет функция запросав контроллере, например, к чему ведет URL.
  3. $ foo-> load-> helper ('syslog_helper') - используйте свойство load (экземпляр загрузчика) длявызовите его вспомогательный метод, передав имя вспомогательного класса в виде строки.Вспомогательный метод должен требовать файл класса, а затем создать экземпляр этого класса.new $class
  4. $ this-> obj -> $ class = new $ class; - тогда этот экземпляр присваивается динамическому свойству, названному так же, как было передано в
  5. $ this-> obj -> $ class - Волшебный метод __set контроллера запускается, сохраняя экземпляр помощника в Controler->data[$helper]
  6. $ 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. По сути, они просто получают доступ к одним и тем же данным по-разному.

Ура!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...