我在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
错误。
我做错了什么?我应该只包含文件而不是加载文件吗?
由于
答案 0 :(得分:14)
很明显,你无法直接加载一个抽象类,因为这与抽象类的观点相悖。
您可以将一个抽象类与另一个库一起放在一个文件中,但这有点毫无意义,违背了CI(以及所有良好标准)建议的“一级一档”标准。
您可以在库文件中包含此文件包含include(),也可以设置__autoload()函数来为您执行此操作。 __autoload()的最佳位置是config.php的底部。
答案 1 :(得分:4)
我使用带有CodeIgniter库的抽象类,因为我有一些常用的方法,我希望所有继承的类都可以使用,这些方法本身毫无意义。我不知道我建议的是最佳做法。我怀疑它不是,但我个人觉得它很有用。我是这样做的:
在CodeIgniter应用程序文件夹中创建一个新的 classes 文件夹。
将此文件夹添加到路径中。 (我通常在控制器中执行此操作。)
if (!strstr(get_include_path(), APPPATH . 'classes')) {
ini_set('include_path', get_include_path() . ':' . APPPATH . 'classes');
}
在 classes 文件夹中创建抽象类或其他类。
创建扩展的CodeIgniter库:
require_once('an_abstract_class.php');
class concrete_library extends an_abstract_class {
正常使用该库:
$this->load->library('concrete_library');
这应该可以解决问题。我希望这很有用。
答案 2 :(得分:3)
确定。我知道这已经很晚了,但我相信很多人对此都有疑问。
这实际上是核心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类完全相同,但最重要的是现在这个类将接管所有加载方法而不是原始方法。
现在我们需要做的就是为loader类提供知道它是否正在加载和实例化一个具体类的方法,或者它是否只包含一个抽象类。
有两种方法可以处理任何库的加载:
方法1)public function library
方法2)protected function _ci_load_class
如果第一个参数是数组,方法1通过迭代自身来处理传递给它的所有参数,确保提供的数据是干净的,并且如果不满足某些条件,则阻止采取任何操作。 / p>
方法2处理必要资产的实际加载,错误处理等。
我们可以通过在新的MY_Loader类中重新定义方法来覆盖方法1和2的行为。我通过创建原始方法的几乎精确的副本来完成此操作,但添加了第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");
?>
答案 3 :(得分:1)
我没有看到任何带有CI的抽象类Web的例子,所以我想确认你可以有一个抽象库。对于为什么抽象类有用,OOP有很好的理由是OOP的基础。从根本上说,我要确保儿童班遵循一定的一致性。
如果您需要一个示例,请告诉我,因为您手动必须包含抽象类,请确保只执行一次,这样您就不会遇到重新声明类的问题。
另外不要忘记,如果您在Abstract类中有静态函数或变量,您仍然可以直接访问它而无需加载类,如下所示
AbstractClass::static_method_you_want_to_call();
答案 4 :(得分:0)
我发现在Codeigniter中使用抽象类的简单方法。只需按照以下步骤。转到系统文件夹中的库
系统->库-> lib.php
abstract class B
{
public function lib1()
{
echo "This is library 1";
}
public function lib2()
{
echo "This is library 1";
}
}
class CI_lib extends B
{
public function libs(){
$this->lib1();
}
}
然后从Controller调用该lib。