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

I have 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:
Create a new classes folder in the CodeIgniter application folder.
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');
}
Create the abstract classes, or other classes, in the classes folder.
Create an extended CodeIgniter library:
require_once('an_abstract_class.php');
class concrete_library extends an_abstract_class {
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
Create an abstract class and dont link it with CI just name it with simple word without CI_
Create an another class name it with the same word as you give name to your file. As shown in code below
Extend that class with abstract class.
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.

Related

add more methods to class using include_once [duplicate]

I want to make a PHP class, lets say Myclass.php. Now inside that class I want to define just the class itself and some instance variables. But all the methods must come from a Myclass_methods.php file. Can I just include that file into the class body?
I have good reasons why I want to seperate this. In short, I'll have a backend in which I can change the business logic of a class, while all other things must remain untouched. The system maintains all the ORM and other stuff for me.
But if this is a bad idea, it might be better to re-generate the whole class file after editing the business logic (so, the user-defined methods in this case).
Performance question: If during one request Myclass.php is included just once, actually that Myclass_methods.php should also be included just once. Might be wrong. Experts?
No. You cannot include files in the class body.
In a file defining a class, you may only include files in a method body or outside the class body.
From your description I take you want this:
<?php // MyClass.php
class MyClass
{
protected $_prop;
include 'myclass-methods.php';
}
<?php // myclass-methods.php
public function myMethod()
{
$this->$_prop = 1;
}
Running this code will result in
Parse error: syntax error, unexpected T_INCLUDE, expecting T_FUNCTION
What is possible though is this
<?php // MyClass.php
class MyClass
{
protected $_prop;
public function __construct() // or any other method
{
include 'some-functions.php';
foo($b); // echoes 'a';
}
}
<?php // some-functions.php
$b = 'a';
function foo($str)
{
echo $str;
}
Doing it this way, will import the contents of the include file into the method scope, not the class scope. You may include functions and variables in the include file, but not methods. You could but should not put entire scripts into it as well and change what the method does, e.g.
<?php // MyClass.php
// ...
public function __construct($someCondition)
{
// No No Code here
include ($someCondition === 'whatever') ? 'whatever.php' : 'default.php';
}
// ...
<?php // whatever.php
echo 'whatever';
<?php // default.php
echo 'foo';
However, patching the class this way to exhibit different behavior is not how you should do it in OOP. It's just plain wrong and should make your eyes bleed.
Since you want to dynamically change behavior, extending the class is also not a good option (see below why). What you really will want to do is write an interface and make your class use objects implementing this interface, thus making sure the appropriate methods are available. This is called a Strategy Pattern and works like this:
<?php // Meowing.php
interface Meowing
{
public function meow();
}
Now you got the contract that all Meowing Behaviors must obey, namely having a meow method. Next define a Meowing Behavior:
<?php // RegularMeow.php
class RegularMeow implements Meowing
{
public function meow()
{
return 'meow';
}
}
Now to use it, use:
<?php // Cat.php
class Cat
{
protected $_meowing;
public function setMeowing(Meowing $meowing)
{
$this->_meowing = $meowing;
}
public function meow()
{
$this->_meowing->meow()
}
}
By adding the Meowing TypeHint to setMeowing, you make sure that the passed param implements the Meowing interface. Let's define another Meowing Behavior:
<?php // LolkatMeow.php
class LolkatMeow implements Meowing
{
public function meow()
{
return 'lolz xD';
}
}
Now, you can easily interchange behaviors like this:
<?php
require_once 'Meowing.php';
require_once 'RegularMeow.php';
require_once 'LolkatMeow.php';
require_once 'Cat.php';
$cat = new Cat;
$cat->setMeowing(new RegularMeow);
echo $cat->meow; // outputs 'meow';
// now to change the behavior
$cat->setMeowing(new LolkatMeow);
echo $cat->meow; // outputs 'lolz xD';
While you also could have solved the above with inheritance by defining an abstract BaseCat and meow method and then deriving concrete RegularCat and Lolkat classes from that, you have to consider what you want to achieve. If your cats will never change the way they meow, go ahead and use inheritance, but if your RegularCat and Lolkat is supposed to be able to do arbitrary meows, then use the Strategy pattern.
For more design patterns in PHP, check these resources:
http://www.php.net/manual/en/language.oop5.patterns.php
http://www.ibm.com/developerworks/library/os-php-designptrns/
http://www.fluffycat.com/PHP-Design-Patterns/
http://sourcemaking.com/design_patterns
Might it not be an idea to create the core class with the relevant base functionality and then extend this with the required methods - it seems like a more logical approach.
I'll start by saying I'm not too clear why this problem is not best solved using a base class containing the methods, subclasses containing the data, and dynamic class loading. I'll assume you have a good reason.
Once your provider supports PHP 5.4 you can do what you want using traits.
Code File:
if ($pet === 'dog') include 'dog.php';
elseif ($pet === 'cat') include 'cat.php';
else die('Unknown pet');
class Pet {
use PetSounds;
}
$myPet = new Pet();
$myPet->speak();
File cat.php
trait PetSounds {
function speak() { echo 'meow'; }
}
File dog.php
trait PetSounds {
function speak() { echo 'woof'; }
}
You could make this even cleaner by naming both include files the same, putting them in different subdirectories, and using set_include_path() or defining an __autoload() function to select between them. Like I said though, this same problem could be solved better using inheritance. If you have a multiple-inheritance type problem though, if for instance you have four kinds of pets with five kinds of colors with three hair types and you need a different combination of methods for each of the 60 different classes, this is the right solution.
5.4 is currently just a Release Candidate (as of 2/24/2012) and even once released most hosts will not support it for many months - mine took 18 months after 5.3 was released before they would support it. Until then you must write entirely separate and complete class files. You can however format your classes with an eventual change to traits in mind.
Right now you can partially get what you want using magic methods and have an easy upgrade to traits when they are available.
Code File:
if ($pet === 'dog') include 'dog.php';
elseif ($pet === 'cat') include 'cat.php';
else die('Unknown pet');
class Pet {
public function __call($name, array $arguments)
{
array_unshift($arguments, $this);
return call_user_func_array("TraitFunc_$name", $arguments);
}
}
$myPet = new Pet();
$myPet->speak();
File cat.php
function TraitFunc_speak(Pet $that) { echo 'meow'; }
File dog.php
function TraitFunc_speak(Pet $that) { echo 'woof'; }
You are limited however in that your functions can not access private and protected class properties and methods and you can not use this method to provide magic methods such as __get(). Traits will solve both of those limitations.
What about using traits for this? Would that be an acceptable option? This is something I am currently experimenting with and it seems to work quite while.
A simplified version of what I am doing is basically like this. I have an application with shared core files and multiple projects. Within those projects i have modules. I want to have functions that are available for the entire project on a core level but only for that specific project.
My project controller
if(is_file(PROJECT_PATH.'/project_extensions.trait.php')){
// additional functions for this specific project
require_once(PROJECT_PATH.'/project_extensions.trait.php');
}else{
// no additional functions
trait Extensions{};
}
Class Project{
USE Extensions;
// default functions shared between all projects
function shared_stuff(){
}
}
Extensions file
trait Extensions{
// project-specific extensions
function this_project_only(){
echo 'Project Only';
}
}
Module file in the project
class MyModule extends Modules{ // modules extends projects in a different class not relevant here
function do_something(){
echo $this->project_only();
}
}
Since PHP5.4 release you can create dynamic objects like this: https://github.com/ptrofimov/jslikeobject
But this is scarcely the best practice.
Reviving an old question but this is a fairly simple solution. Do you need the common function calls to be exclusive to your class? If not, simply include your common function file(s) within the same scope as your class. You will need to create methods in your class but they will only need to call the common function. Here's a simple SOAP server example:
<?php
include 'post_function.php';
$server = new SoapServer( null, array('uri' => "http://localhost/") );
$server->setClass( 'postsoapclass' );
$server->handle();
class postsoapclass
{
public function animalNoise( $animal )
{
return get_animal_noise($animal);
}
}
?>
post_function.php
<?php
function get_animal_noise($animal)
{
if(strtolower(trim($animal)) == 'pig')
{
return 'Oink';
}
else
{
return 'This animal is mute';
}
}
?>
I have had to do what you are describing in cases where I maintain a free version and a premium version of the same software. Because, as #Gordon noted, you cannot do exactly this:
class SomeClass {
premium_file = "premium.php";
if (file_exists($premium_file)) {
require($premium_file);
}
Instead I do this:
premium_file = "premium.php";
if (file_exists($premium_file)) {
require($premium_file);
}
class SomeClass {
...
For functions you want to reference, create class methods in the main class, and call the included file's method, passing the $this pointer as a parameter. So that I can tell at a glance where functions are, I will prefix the name of the included functions as shown below:
class SomeClass {
...
// Premium functions
public function showlist() {
premium_showlist($this);
}
You can include or require before declaring your class like below:
require 'path-to-file';
class myClass{
function show($uid){
}
}
The answer is yes, for example:
Into class construct, pass to the function (that's into the included file) values as params:
$this->wpd = $this->wpdopt = 'something';
include_once('/common/functions_common.php');
$this->wpdb = wpquery($sql='', $mode='', $this->wpd);
Into the included functions_common.php file:
function wpquery($sql, $mode, $wdp)
{
if(!empty($wdp))
{ return true; } else { return false; }
}
Into class methods:
$sql = "UPDATE ..... SET ... WHERE LOWER(user_email) = . ...";
$this->wpdb = wpquery($sql,'update',$this->wpd);
OR
$retval_var = $this->wpdb = wpquery($sql,'update',$this->wpd);
OR even
$this->var = $this->wpdb = wpquery($sql,'update',$this->wpd);
Cheers to all the lovely and cool people
I came across this recently, and came up with a solution, that helped in my case. I wanted many functions in a class, but the class became bloated, so wanted to separate out the class functions into groups for readability. It took a little time to accomplish, but since the functions of the class didn't rely (much) on $this, I removed "$this" from the class functions and created several helper files to include those functions. When $this was necessary, I could nevertheless move the function into a helper file, by passing $this to the function, adding public set/get functions where necessary. It's a hack, but it's sure to help someone
class myClass
{
var x;
function myClass()
{
$this->x = 0;
}
function myFunc1Group1()
{
$x = $this->x;
$x++;
$this->x = $x;
}
function myFunc2Group1(){}
function myFunc1Group2(){}
function myFunc2Group2(){}
}
can be worked around to
class myClass
{
var x;
function myClass()
{
$this->x = 0;
}
function doSomething()
{
// not called on $this but takes $this as a parameter
myFunc1Group1($this);
}
}
and helper function set 1
function myFunc1Group1($THIS_OBJECT)
{
$x = $THIS_OBJECT->getX();
$x++;
$THIS_OBJECT->setX($x);
}
function myFunc2Group1($THIS_OBJECT){}
and helper function set 2, etc.
Probably not the best route in all cases, but helped me out a lot. Basically the class functions were only to construct and delegate, and the calculations were put into helpers.

PHP How to create helper function for class method

I would like to create some global functions that make use of an existing class method. I don't have all of the supporting functionality for the getConfig() method shown, but it's irrelevant to my question:
class Init {
public function getConfig($type) {
if (isset($this->config[$type])) {
return $this->config[$type];
}
$file = dirname(__FILE__, 3).'/app/config/'.$type.'.php';
if (!file_exists($file)) {
return false;
}
$contents = include($file);
$this->config[$type] = $contents;
return $this->config[$type];
} // End getConfig
}
// class Init gets instantiated in my bootstrap file
Now, in my helpers.php file:
function app_config($key) {
$init = new Init(); // Is there any better way of doing this?
return $init->getConfig('app')[$key];
}
So, the helper function app_config may be used in 20 places throughout the app for any given request. Not to mention other helper functions that utilize the Init class as well as other classes.
What is the best way to setup these helper functions? Should they be instantiating these classes over and over again? (This makes it extremely difficult with classes which have specific parameters passed to the constructor)

How can I avoid two Class with same name?

In my php file i am doing it this way
pagecontroller.php
include_once(RUDRA."/controller/AbstractTemplateController.php");
if (file_exists(get_include_path() . CONTROLLER_PATH . "/TemplateController.php" )) {
include_once (CONTROLLER_PATH . "/TemplateController.php");
} else {
include_once (RUDRA . "/controller/TemplateController.php");
}
in TemplateController.php a class named 'TemplateController extends AbstractTemplateController' is defined, if a developer has already defined a class TemplateController which also extends AbstractTemplateController then it will use that otherwise it will fallback to default definition.
then in other files i will simply use something like this
include_once("pagecontroller.php")
$c = new TemplateController();
is there any better way to do this?
since I am including two files AbstractTemplateController.php & TemplateController.php in both cases, I cpuld have written both class definitions in same file which would have saved one include(if there is no custom TemplateController.php)?
I tried writing AbstractTemplateController & TemplateController in one single file but if then developer has defined his own TemplateController it creates two classes with same name situation.
pupose is to have atleast one definition to be there, if customDefinition does not exists then only use default one. and this code is to be abstract.
in the beginning if CustomClass exists (in a specific folder) then that the definition to be used, else use default one (which is nothing but simply extends AbstractOne)
CONTROLLER_PATH . "/TemplateController.php"
class TemplateController extends AbstractTemplateController {
/* over-ridden method of AbstractTemplateController
*/
public function invoke($abc,$def){
echo $abc . " " .$def;
}
}
RUDRA . "/controller/TemplateController.php"
class TemplateController extends AbstractTemplateController {
// nothing at all this is simply to make sure TemplateController class is available
// for others to use.
}
Use namespaces and convention.
E.g. you could check if there's a TemplateController-class present that extends the AbstractTemplateController that's different from your namespace (As your implementation will be specific for your namespace), if there isn't ; fall back to your implementation of the TemplateController.
http://php.net/manual/en/language.namespaces.php
php provides a function for not letting you load/write a class more then once.
bool class_exists ( string $class_name );
example is :
<?php
function __autoload($class)
{
include($crigger_error("Unable to load class: $class", E_USER_WARNING);
}
}
if (class_exists('MyClass')) {
$myclass = new MyClass();
}lass . '.php');
// Check to see whether the include declared the class
if (!class_exists($class, false)) {
trigger_error("Unable to load class: $class", E_USER_WARNING);
}
}
if (class_exists('MyClass')) {
$myclass = new MyClass();
}
?>
in above example autoload is used, you could do it without autoload this way :
<?php
// Check that the class exists before trying to use it
if (class_exists('MyClass')) {
$myclass = new MyClass();
}
?>
still i am saying you better get habit of using namespaces. they are awesome and work every where.

How to test controllers with CodeIgniter?

I have a PHP web application built with CodeIgniter MVC framework. I wish to test various controller classes. I'm using Toast for unit testing. My controllers have no state, everything they process is either saved into session or passed to view to display. Creating a mock session object and testing whether that works properly is straightforward (just create a mock object and inject it with $controller->session = $mock).
What I don't know, is how to work with views. In CodeIgniter, views are loaded as:
$this->load->view($view_name, $vars, $return);
Since I don't want to alter CI code, I though I could create a mock Loader and replace the original. And here lies the problem, I cannot find a way to derive a new class from CI_Loader.
If I don't include the system/libraries/Loader.php file, the class CI_Loader is undefined and I cannot inherit from it:
class Loader_mock extends CI_Loader
If I do include the file (using require_once), I get the error:
Cannot redeclare class CI_Loader
Looks like CI code itself does not use require_once from whatever reason.
Does anyone here have experience with unit testing CodeIgniter powered applications?
Edit: I tried to inject a real loader object at run-time into a mock class, and redirect all calls and variables with __call, __set, __get, __isset and __unset. But, it does not seem to work (I don't get any errors though, just no output, i.e. blank page from Toast). Here's the code:
class Loader_mock
{
public $real_loader;
public $varijable = array();
public function Loader_mock($real)
{
$this->real_loader = $real;
}
public function __call($name, $arguments)
{
return $this->real_loader->$name($arguments);
}
public function __set($name, $value)
{
return $this->real_loader->$name = $value;
}
public function __isset($name)
{
return isset($this->real_loader->$name);
}
public function __unset($name)
{
unset($this->loader->$name);
}
public function __get($name)
{
return $this->real_loader->$name;
}
public function view($view, $vars = array(), $return = FALSE)
{
$varijable = $vars;
}
}
Alternatively, you could do this:
$CI =& get_instance();
$CI = load_class('Loader');
class MockLoader extends CI_Loader
{
function __construct()
{
parent::__construct();
}
}
Then in your controller do $this->load = new MockLoader().
My current solution is to alter the CodeIgniter code to use require_once instead of require. Here's the patch I'm going to send to CI developers in case someone needs to do the same until they accept it:
diff --git a/system/codeigniter/Common.php b/system/codeigniter/Common.php
--- a/system/codeigniter/Common.php
+++ b/system/codeigniter/Common.php
## -100,20 +100,20 ## function &load_class($class, $instantiate = TRUE)
// folder we'll load the native class from the system/libraries folder.
if (file_exists(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT))
{
- require(BASEPATH.'libraries/'.$class.EXT);
- require(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT);
+ require_once(BASEPATH.'libraries/'.$class.EXT);
+ require_once(APPPATH.'libraries/'.config_item('subclass_prefix').$class.EXT);
$is_subclass = TRUE;
}
else
{
if (file_exists(APPPATH.'libraries/'.$class.EXT))
{
- require(APPPATH.'libraries/'.$class.EXT);
+ require_once(APPPATH.'libraries/'.$class.EXT);
$is_subclass = FALSE;
}
else
{
- require(BASEPATH.'libraries/'.$class.EXT);
+ require_once(BASEPATH.'libraries/'.$class.EXT);
$is_subclass = FALSE;
}
}
I can't help you much with the testing, but I can help you extend the CI library.
You can create your own MY_Loader class inside /application/libraries/MY_Loader.php.
<?php
class MY_Loader extends CI_Loader {
function view($view, $vars = array(), $return = FALSE) {
echo 'My custom code goes here';
}
}
CodeIgniter will see this automatically. Just put in the functions you want to replace in the original library. Everything else will use the original.
For more info check out the CI manual page for creating core system classes.
I'm impressed by the code you are trying to use.
So now I'm wondering how the 'Hooks' class of CodeIgniter could be of any help to your problem?
http://codeigniter.com/user_guide/general/hooks.html
Kind regards,
Rein Groot
The controller should not contain domain logic, so unit tests make no sense here.
Instead I would test the controllers and views with acceptance tests.

Can I include code into a PHP class?

I want to make a PHP class, lets say Myclass.php. Now inside that class I want to define just the class itself and some instance variables. But all the methods must come from a Myclass_methods.php file. Can I just include that file into the class body?
I have good reasons why I want to seperate this. In short, I'll have a backend in which I can change the business logic of a class, while all other things must remain untouched. The system maintains all the ORM and other stuff for me.
But if this is a bad idea, it might be better to re-generate the whole class file after editing the business logic (so, the user-defined methods in this case).
Performance question: If during one request Myclass.php is included just once, actually that Myclass_methods.php should also be included just once. Might be wrong. Experts?
No. You cannot include files in the class body.
In a file defining a class, you may only include files in a method body or outside the class body.
From your description I take you want this:
<?php // MyClass.php
class MyClass
{
protected $_prop;
include 'myclass-methods.php';
}
<?php // myclass-methods.php
public function myMethod()
{
$this->$_prop = 1;
}
Running this code will result in
Parse error: syntax error, unexpected T_INCLUDE, expecting T_FUNCTION
What is possible though is this
<?php // MyClass.php
class MyClass
{
protected $_prop;
public function __construct() // or any other method
{
include 'some-functions.php';
foo($b); // echoes 'a';
}
}
<?php // some-functions.php
$b = 'a';
function foo($str)
{
echo $str;
}
Doing it this way, will import the contents of the include file into the method scope, not the class scope. You may include functions and variables in the include file, but not methods. You could but should not put entire scripts into it as well and change what the method does, e.g.
<?php // MyClass.php
// ...
public function __construct($someCondition)
{
// No No Code here
include ($someCondition === 'whatever') ? 'whatever.php' : 'default.php';
}
// ...
<?php // whatever.php
echo 'whatever';
<?php // default.php
echo 'foo';
However, patching the class this way to exhibit different behavior is not how you should do it in OOP. It's just plain wrong and should make your eyes bleed.
Since you want to dynamically change behavior, extending the class is also not a good option (see below why). What you really will want to do is write an interface and make your class use objects implementing this interface, thus making sure the appropriate methods are available. This is called a Strategy Pattern and works like this:
<?php // Meowing.php
interface Meowing
{
public function meow();
}
Now you got the contract that all Meowing Behaviors must obey, namely having a meow method. Next define a Meowing Behavior:
<?php // RegularMeow.php
class RegularMeow implements Meowing
{
public function meow()
{
return 'meow';
}
}
Now to use it, use:
<?php // Cat.php
class Cat
{
protected $_meowing;
public function setMeowing(Meowing $meowing)
{
$this->_meowing = $meowing;
}
public function meow()
{
$this->_meowing->meow()
}
}
By adding the Meowing TypeHint to setMeowing, you make sure that the passed param implements the Meowing interface. Let's define another Meowing Behavior:
<?php // LolkatMeow.php
class LolkatMeow implements Meowing
{
public function meow()
{
return 'lolz xD';
}
}
Now, you can easily interchange behaviors like this:
<?php
require_once 'Meowing.php';
require_once 'RegularMeow.php';
require_once 'LolkatMeow.php';
require_once 'Cat.php';
$cat = new Cat;
$cat->setMeowing(new RegularMeow);
echo $cat->meow; // outputs 'meow';
// now to change the behavior
$cat->setMeowing(new LolkatMeow);
echo $cat->meow; // outputs 'lolz xD';
While you also could have solved the above with inheritance by defining an abstract BaseCat and meow method and then deriving concrete RegularCat and Lolkat classes from that, you have to consider what you want to achieve. If your cats will never change the way they meow, go ahead and use inheritance, but if your RegularCat and Lolkat is supposed to be able to do arbitrary meows, then use the Strategy pattern.
For more design patterns in PHP, check these resources:
http://www.php.net/manual/en/language.oop5.patterns.php
http://www.ibm.com/developerworks/library/os-php-designptrns/
http://www.fluffycat.com/PHP-Design-Patterns/
http://sourcemaking.com/design_patterns
Might it not be an idea to create the core class with the relevant base functionality and then extend this with the required methods - it seems like a more logical approach.
I'll start by saying I'm not too clear why this problem is not best solved using a base class containing the methods, subclasses containing the data, and dynamic class loading. I'll assume you have a good reason.
Once your provider supports PHP 5.4 you can do what you want using traits.
Code File:
if ($pet === 'dog') include 'dog.php';
elseif ($pet === 'cat') include 'cat.php';
else die('Unknown pet');
class Pet {
use PetSounds;
}
$myPet = new Pet();
$myPet->speak();
File cat.php
trait PetSounds {
function speak() { echo 'meow'; }
}
File dog.php
trait PetSounds {
function speak() { echo 'woof'; }
}
You could make this even cleaner by naming both include files the same, putting them in different subdirectories, and using set_include_path() or defining an __autoload() function to select between them. Like I said though, this same problem could be solved better using inheritance. If you have a multiple-inheritance type problem though, if for instance you have four kinds of pets with five kinds of colors with three hair types and you need a different combination of methods for each of the 60 different classes, this is the right solution.
5.4 is currently just a Release Candidate (as of 2/24/2012) and even once released most hosts will not support it for many months - mine took 18 months after 5.3 was released before they would support it. Until then you must write entirely separate and complete class files. You can however format your classes with an eventual change to traits in mind.
Right now you can partially get what you want using magic methods and have an easy upgrade to traits when they are available.
Code File:
if ($pet === 'dog') include 'dog.php';
elseif ($pet === 'cat') include 'cat.php';
else die('Unknown pet');
class Pet {
public function __call($name, array $arguments)
{
array_unshift($arguments, $this);
return call_user_func_array("TraitFunc_$name", $arguments);
}
}
$myPet = new Pet();
$myPet->speak();
File cat.php
function TraitFunc_speak(Pet $that) { echo 'meow'; }
File dog.php
function TraitFunc_speak(Pet $that) { echo 'woof'; }
You are limited however in that your functions can not access private and protected class properties and methods and you can not use this method to provide magic methods such as __get(). Traits will solve both of those limitations.
What about using traits for this? Would that be an acceptable option? This is something I am currently experimenting with and it seems to work quite while.
A simplified version of what I am doing is basically like this. I have an application with shared core files and multiple projects. Within those projects i have modules. I want to have functions that are available for the entire project on a core level but only for that specific project.
My project controller
if(is_file(PROJECT_PATH.'/project_extensions.trait.php')){
// additional functions for this specific project
require_once(PROJECT_PATH.'/project_extensions.trait.php');
}else{
// no additional functions
trait Extensions{};
}
Class Project{
USE Extensions;
// default functions shared between all projects
function shared_stuff(){
}
}
Extensions file
trait Extensions{
// project-specific extensions
function this_project_only(){
echo 'Project Only';
}
}
Module file in the project
class MyModule extends Modules{ // modules extends projects in a different class not relevant here
function do_something(){
echo $this->project_only();
}
}
Since PHP5.4 release you can create dynamic objects like this: https://github.com/ptrofimov/jslikeobject
But this is scarcely the best practice.
Reviving an old question but this is a fairly simple solution. Do you need the common function calls to be exclusive to your class? If not, simply include your common function file(s) within the same scope as your class. You will need to create methods in your class but they will only need to call the common function. Here's a simple SOAP server example:
<?php
include 'post_function.php';
$server = new SoapServer( null, array('uri' => "http://localhost/") );
$server->setClass( 'postsoapclass' );
$server->handle();
class postsoapclass
{
public function animalNoise( $animal )
{
return get_animal_noise($animal);
}
}
?>
post_function.php
<?php
function get_animal_noise($animal)
{
if(strtolower(trim($animal)) == 'pig')
{
return 'Oink';
}
else
{
return 'This animal is mute';
}
}
?>
I have had to do what you are describing in cases where I maintain a free version and a premium version of the same software. Because, as #Gordon noted, you cannot do exactly this:
class SomeClass {
premium_file = "premium.php";
if (file_exists($premium_file)) {
require($premium_file);
}
Instead I do this:
premium_file = "premium.php";
if (file_exists($premium_file)) {
require($premium_file);
}
class SomeClass {
...
For functions you want to reference, create class methods in the main class, and call the included file's method, passing the $this pointer as a parameter. So that I can tell at a glance where functions are, I will prefix the name of the included functions as shown below:
class SomeClass {
...
// Premium functions
public function showlist() {
premium_showlist($this);
}
You can include or require before declaring your class like below:
require 'path-to-file';
class myClass{
function show($uid){
}
}
The answer is yes, for example:
Into class construct, pass to the function (that's into the included file) values as params:
$this->wpd = $this->wpdopt = 'something';
include_once('/common/functions_common.php');
$this->wpdb = wpquery($sql='', $mode='', $this->wpd);
Into the included functions_common.php file:
function wpquery($sql, $mode, $wdp)
{
if(!empty($wdp))
{ return true; } else { return false; }
}
Into class methods:
$sql = "UPDATE ..... SET ... WHERE LOWER(user_email) = . ...";
$this->wpdb = wpquery($sql,'update',$this->wpd);
OR
$retval_var = $this->wpdb = wpquery($sql,'update',$this->wpd);
OR even
$this->var = $this->wpdb = wpquery($sql,'update',$this->wpd);
Cheers to all the lovely and cool people
I came across this recently, and came up with a solution, that helped in my case. I wanted many functions in a class, but the class became bloated, so wanted to separate out the class functions into groups for readability. It took a little time to accomplish, but since the functions of the class didn't rely (much) on $this, I removed "$this" from the class functions and created several helper files to include those functions. When $this was necessary, I could nevertheless move the function into a helper file, by passing $this to the function, adding public set/get functions where necessary. It's a hack, but it's sure to help someone
class myClass
{
var x;
function myClass()
{
$this->x = 0;
}
function myFunc1Group1()
{
$x = $this->x;
$x++;
$this->x = $x;
}
function myFunc2Group1(){}
function myFunc1Group2(){}
function myFunc2Group2(){}
}
can be worked around to
class myClass
{
var x;
function myClass()
{
$this->x = 0;
}
function doSomething()
{
// not called on $this but takes $this as a parameter
myFunc1Group1($this);
}
}
and helper function set 1
function myFunc1Group1($THIS_OBJECT)
{
$x = $THIS_OBJECT->getX();
$x++;
$THIS_OBJECT->setX($x);
}
function myFunc2Group1($THIS_OBJECT){}
and helper function set 2, etc.
Probably not the best route in all cases, but helped me out a lot. Basically the class functions were only to construct and delegate, and the calculations were put into helpers.

Categories