如何在Codeigniter框架中添加抽象类库?

时间:2011-02-23 22:23:03

标签: php codeigniter

我在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错误。

我做错了什么?我应该只包含文件而不是加载文件吗?

由于

5 个答案:

答案 0 :(得分:14)

很明显,你无法直接加载一个抽象类,因为这与抽象类的观点相悖。

您可以将一个抽象类与另一个库一起放在一个文件中,但这有点毫无意义,违背了CI(以及所有良好标准)建议的“一级一档”标准。

您可以在库文件中包含此文件包含include(),也可以设置__autoload()函数来为您执行此操作。 __autoload()的最佳位置是config.php的底部。

答案 1 :(得分:4)

我使用带有CodeIgniter库的抽象类,因为我有一些常用的方法,我希望所有继承的类都可以使用,这些方法本身毫无意义。我不知道我建议的是最佳做法。我怀疑它不是,但我个人觉得它很有用。我是这样做的:

  1. 在CodeIgniter应用程序文件夹中创建一个新的 classes 文件夹。

  2. 将此文件夹添加到路径中。 (我通常在控制器中执行此操作。)

    if (!strstr(get_include_path(), APPPATH . 'classes')) {
        ini_set('include_path', get_include_path() . ':' . APPPATH . 'classes');
    }
    
  3. classes 文件夹中创建抽象类或其他类。

  4. 创建扩展的CodeIgniter库:

    require_once('an_abstract_class.php');
    class concrete_library extends an_abstract_class {
    
  5. 正常使用该库:

    $this->load->library('concrete_library');
    
  6. 这应该可以解决问题。我希望这很有用。

答案 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中使用抽象类的简单方法。只需按照以下步骤。转到系统文件夹中的库

  1. 创建一个抽象类,不要将其与CI链接在一起,而只需用简单的单词命名即可,而无需CI _
  2. 使用与给文件命名相同的词创建另一个类,为其命名。如下面的代码所示
  3. 用抽象类扩展该类。
  4. 然后通过您的CI_class调用抽象类函数。

系统->库-> 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。