У меня есть следующий код в файле AbstractClass.php
в папке libraries
abstract class AbstractClass { abstract protected doSomething (); } class ConcreteClass extends AbstractClass { public function doSomething () {}; }
Когда я пытаюсь загрузить AbstractClass
из controllers
следующим образом:
$this->load->library('AbstractClass');
Я получаю Unable to load the requested class: AbstractClass
ошибка Unable to load the requested class: AbstractClass
.
Что я делаю не так? Должен ли я просто включать файл, а не загружать его?
благодаря
Очевидно, что вы не можете загрузить абстрактный класс напрямую, поскольку это противоречит точке абстрактного класса.
Вы можете поместить абстрактный класс в файл вместе с другой библиотекой, но это немного бессмысленно и противоречит стандарту «один класс один», который предлагает CI (и все хорошие стандарты).
Вы можете включить этот файл с include () в файлы вашей библиотеки или настроить функцию __autoload (), чтобы сделать это за вас. Лучшее место для __autoload () – это дно config.php.
Я использую абстрактные классы с библиотеками CodeIgniter, потому что у меня есть общие методы, которые я хочу использовать для всех унаследованных классов, которые сами по себе бессмысленны. Я не знаю, подходит ли то, что я собираюсь предложить. Я подозреваю, что это не так, но я лично считаю это полезным. Вот как я это делаю:
Создайте новую папку классов в папке приложения CodeIgniter.
Добавьте эту папку в путь. (Обычно я делаю это в контроллере.)
if (!strstr(get_include_path(), APPPATH . 'classes')) { ini_set('include_path', get_include_path() . ':' . APPPATH . 'classes'); }
Создайте абстрактные классы или другие классы в папке классов .
Создайте расширенную библиотеку CodeIgniter:
require_once('an_abstract_class.php'); class concrete_library extends an_abstract_class {
Используйте библиотеку как обычно:
$this->load->library('concrete_library');
Это должно делать свое дело. Надеюсь, это полезно.
ОК. Я знаю, что это конец, но я уверен, что у многих людей есть вопросы об этом.
Это фактически ограничение основного класса Loader, поскольку оно пытается создать экземпляр каждого из элементов, определенных первым параметром. Как мы все знаем, абстрактные классы по их самому определению являются абстрактными и не могут быть созданы. Итак, как нам обойти это?
Но самое главное: как мы обойдем это, соблюдая стандарты CodeIgniter?
Поскольку я только начал использовать CodeIgniter, я не могу точно сказать, как Core Extensions были обработаны в прошлом. Однако в самой последней версии инфраструктура CodeIgniter позволит вам расширять и переопределять основные классы путем префикса имени файла с заданным префиксом подкласса (в большинстве случаев «MY_»), за которым следует имя файла, который вы планируете продлить.
* / Приложение / ядро / MY_Loader.php *
<?php if(!defined('BASEPATH')) exit('No direct script access allowed'); class MY_Loader extends CI_Loader{ public function __construct(){ parent::__construct(); } } ?>
Скорее всего, если вы знаете, как использовать абстрактные классы, вы знаете, что это делает. В принципе, этот класс теперь наследует все свойства и методы исходного класса CI_Loader. Вышеприведенный фрагмент кода является технически точным дубликатом исходного класса Loader, но самое главное, что теперь этот класс возьмет на себя все методы загрузки, а не оригинал.
Теперь все, что нам нужно сделать, это предоставить классу загрузчика средства, чтобы знать, загружает ли он и создает ли конкретный класс, или просто включает абстрактный класс.
Существует два метода обработки любых библиотек:
Метод 1) public function library
Способ 2) protected function _ci_load_class
Метод 1 обрабатывает обработку всех переданных ему параметров путем итерации через себя, если первый параметр является массивом, гарантирует, что предоставленные данные являются чистыми, и предотвращает любые действия, если определенные критерии не выполняются.
Метод 2 обрабатывает фактическую загрузку необходимых активов, обработку ошибок и т. Д.
Мы можем переопределить поведение методов 1 и 2, переопределив их в нашем новом классе MY_Loader. Я сделал это, создав почти точные копии исходных методов, но с добавлением 4-го параметра, который – когда true – предотвратит загрузку Loader из заданного класса библиотеки во втором методе. Я также включил дополнительную public function abstract_library
, которая позволит вам явно определить библиотеку как абстрактную в сокращенном виде.
Ниже представлен класс MY_Loader.php. Это не повлияет на существующие вызовы метода библиотеки.
Надеюсь это поможет!
* / Приложение / ядро / MY_Loader.php *
<?php if(!defined('BASEPATH')) exit('No direct script access allowed'); class MY_Loader extends CI_Loader{ public function __construct(){ parent::__construct(); } public function library($library = '', $params = NULL, $object_name = NULL, $is_abstract=false){ if(is_array($library)){ foreach ($library as $class){ $this->library($class, $params); } return; } if($library == '' OR isset($this->_base_classes[$library])){ return FALSE; } if(!is_null($params) && ! is_array($params)){ $params = NULL; } $this->_ci_load_class($library, $params, $object_name, $is_abstract); } public function abstract_library($library=''){ $this->library($library, NULL , NULL, true); } protected function _ci_load_class($class, $params = NULL, $object_name = NULL, $is_abstract=false) { $class = str_replace('.php', '', trim($class, '/')); $subdir = ''; if(($last_slash = strrpos($class, '/')) !== FALSE){ $subdir = substr($class, 0, $last_slash + 1); $class = substr($class, $last_slash + 1); } foreach(array(ucfirst($class), strtolower($class)) as $class){ $subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php'; if(file_exists($subclass)){ $baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php'; if (!file_exists($baseclass)){ log_message('error', "Unable to load the requested class: ".$class); show_error("Unable to load the requested class: ".$class); } if(in_array($subclass, $this->_ci_loaded_files)){ if(!is_null($object_name)){ $CI =& get_instance(); if(!isset($CI->$object_name)){ return $is_abstract ? true : $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); } } $is_duplicate = TRUE; log_message('debug', $class." class already loaded. Second attempt ignored."); return; } include_once($baseclass); include_once($subclass); $this->_ci_loaded_files[] = $subclass; return $is_abstract ? true : $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); } $is_duplicate = FALSE; foreach ($this->_ci_library_paths as $path){ $filepath = $path.'libraries/'.$subdir.$class.'.php'; if(!file_exists($filepath)){ continue; } if(in_array($filepath, $this->_ci_loaded_files)){ if(!is_null($object_name)){ $CI =& get_instance(); if(!isset($CI->$object_name)){ return $is_abstract ? true : $this->_ci_init_class($class, '', $params, $object_name); } } $is_duplicate = TRUE; log_message('debug', $class." class already loaded. Second attempt ignored."); return; } include_once($filepath); $this->_ci_loaded_files[] = $filepath; return $is_abstract ? true : $this->_ci_init_class($class, '', $params, $object_name); } } // END FOREACH if($subdir == ''){ $path = strtolower($class).'/'.$class; return $this->_ci_load_class($path, $params, $is_abstract); } if($is_duplicate == FALSE){ log_message('error', "Unable to load the requested class: ".$class); show_error("Unable to load the requested class: ".$class); } } } ?>
Загрузка абстрактной библиотеки:
<?php $this->load->library("My_Abstract_Library", NULL, NULL, true); /* -- OR -- */ $this->load->abstract_library("My_Abstract_Library"); ?>
Я не видел примеров в Интернете абстрактных классов с CI, поэтому я хотел подтвердить, что вы можете иметь абстрактную библиотеку. Есть очень веские причины, которые являются основополагающими для ООП относительно того, почему абстрактные классы полезны. По сути, для меня, чтобы детские классы соответствовали определенным требованиям.
Дайте мне знать, если вам нужен пример, так как вы должны вручную включить абстрактный класс, убедитесь, что вы делаете это только один раз, чтобы не возникало проблем с классами повторного использования.
Также не забывайте, что у вас есть статическая функция или переменная в классе Abstract, вы можете получить к ней доступ напрямую, не загружая класс, как показано ниже.
AbstractClass::static_method_you_want_to_call();