开发者

How do you add abstract class library in the Codeigniter framework?

开发者 https://www.devze.com 2023-02-13 14:35 出处:网络
I hav开发者_StackOverflow社区e the following code in file called AbstractClass.php in the libraries folder

I hav开发者_StackOverflow社区e the following code in file called AbstractClass.php in the libraries folder

abstract class AbstractClass {
  abstract protected doSomething ();
}

class ConcreteClass extends AbstractClass {
  public function doSomething () {};

}

When I try to load the AbstractClass from controllers as follows:

$this->load->library('AbstractClass');

I get Unable to load the requested class: AbstractClass error.

What am I doing wrong? Should I just include the file rather than loading it?

Thanks


Well obviously you cannot load an abstract class directly as this goes against the point of an abstract class.

You can put an abstract class in a file along with another library, but that is a bit pointless and goes against the "one class one file" standard that CI (and all good standards) suggest.

You can include this file with an include() in your library files, or set up an __autoload() function to do it for you. Best place for an __autoload() is the bottom of config.php.


I use abstract classes with CodeIgniter libraries because I have common methods which I want all inherited classes to use which are meaningless on their own. I don't know if what I'm about to suggest is best practise. I suspect it's not, but I personally find it useful. Here's how I do it:

  1. Create a new classes folder in the CodeIgniter application folder.

  2. Add this folder to the path. (I usually do this in the controller.)

    if (!strstr(get_include_path(), APPPATH . 'classes')) {
        ini_set('include_path', get_include_path() . ':' . APPPATH . 'classes');
    }
    
  3. Create the abstract classes, or other classes, in the classes folder.

  4. Create an extended CodeIgniter library:

    require_once('an_abstract_class.php');
    class concrete_library extends an_abstract_class {
    
  5. Use the library as normal:

    $this->load->library('concrete_library');
    

That should do the trick. I hope this is useful.


Ok. I know this is WAY late, but I'm sure many people are having questions about this.

This is actually a limitation of the core Loader class, as it attempts to instantiate each of the items defined by the first parameter. As we all know, Abstract Classes by their very definition are Abstract and CANNOT be instantiated. So how do we get around this?

But most importantly: How do we get around this while conforming to the CodeIgniter Standards?

Since I've only just started using CodeIgniter, I can't really say for certain how Core Extensions were handled in the past. However, in the most recent version, the CodeIgniter framework will allow you to extend and override its core classes by Prefixing the filename with your defined Subclass Prefix (in most cases "MY_") followed by the name of the file you plan on extending.

*/application/core/MY_Loader.php*

<?php
if(!defined('BASEPATH')) exit('No direct script access allowed');

class MY_Loader extends CI_Loader{
    public function __construct(){
        parent::__construct();
    }
}
?>

Chances are good that if you know how to utilize Abstract Classes, you know what this does. Basically, this Class now inherits all properties and methods of the original CI_Loader class. The code snippet above is technically an exact duplicate of the original Loader Class, but the most important thing here is that now this class will take over all load methods rather than the original.

Now all we need to do is provide the loader class with the means to know if it's loading and instantiating a concrete class, or if it's simply including an abstract class.

There are two methods that handle the loading of any Libraries:

Method 1) public function library
Method 2) protected function _ci_load_class

Method 1 handles the processing of all parameters passed to it by iterating through itself if the first parameter is an array, makes sure the data provided is clean, and prevents any actions from being taken if certain criteria aren't met.

Method 2 handles the actual loading of the necessary assets, error handling, etc.

We can override the behavior of methods 1 and 2 by redefining them within our new MY_Loader Class. I've done this by creating almost exact replicas of the original methods, but with the addition of a 4th parameter that - when true - will prevent the Loader from instantiating the defined Library Class in the second method. I've also included an additional method public function abstract_library that will allow you to explicitly define the Library as Abstract in shorthand fashion.

The following is the MY_Loader.php class in its entirety. This will not affect any existing calls to the library method.

Hope this helps!

*/application/core/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);
        }
    }
}
?>

Loading an abstract library:

<?php
$this->load->library("My_Abstract_Library", NULL, NULL, true);
/* -- OR -- */
$this->load->abstract_library("My_Abstract_Library");
?>


I haven't seen any examples around the web of Abstract classes with CI so I wanted to confirm that you can have an Abstract library. There are very good reasons which are fundamental to OOP as to why Abstract classes are useful. Fundamentally for me to ensure the child classes follow certain consistencies.

Let me know if you need an example, as you manually have to include the abstract class make sure you only do it once so you don't get issues with redeclaring classes.

Also don't forget if you have a static function or variable in the Abstract class you can still access it directly without having to load the class as in the below

AbstractClass::static_method_you_want_to_call();


I have found a simple way to use an abstract classes in Codeigniter. Just follow these steps. Go to libraries in system folder

  1. Create an abstract class and dont link it with CI just name it with simple word without CI_
  2. Create an another class name it with the same word as you give name to your file. As shown in code below
  3. Extend that class with abstract class.
  4. Then call abstract class function through your CI_class.

System -> libraries -> 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();
       }
   }

Then call that lib from Controller.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号