开发者

PHP Object Extension $this->some_object->method

I am trying to make a script in which different classes (e.g. Database, Utilities, Config) are all used to form one central Main class. I have tried extending a chain of them:

Main -> Utilities -> Database -> Configuration

But how can I set the different parts so that they can be called like this:

<?php

     $this->db->select("WA开发者_JAVA百科FFLES");
     echo($this->config->app_path);

?>


You could create a global class that does you basic initializing

class Base {

 $var1, var2;

 public function __construct() {
   $this->var1 = new DB();
   $this->var2 = new Config();
   ....
 }
}

Then your classes can extend the base class and have access to the data

class Foo extends Base {

  public function bar() {
    $this->var1->someOpertaion();
  }
}


You need to declare each new object as variable in your Main Class like:

class Main{

    private $db = NULL;
    private $config = NULL;

    $this->db = new Database;
    $this->config = new Config;

}

etc.

While i'm not a professional coder i'll considering a better approach than this. This kind of object-handling can cause a bloated main class and in the worst case you may face some performance issues.


1) use __autoload or spl_autoload_register to load classes

2) use magic methods, to call function when getting unknown property. Following examples demonstrates how to use __get and dynamicaly initialize object only when you use them.

//use __autoload to load db and config class when they are called.
class db{
  function lol(){
    echo 'Hello from db->lol() <br />';
  }
}
class config{
  function lol(){
    echo 'Hello from config->lol() <br />';
  }
}


//Manager class to use with classes where you want to access other object trough $this
class Manager{
  private $_instances=array();
  function __get($name){
    //if instance does not exists, create one
    if (!isset($this->_instances[$name])){
      $this->_instances[$name]=new $name();
    }

    //return instance
    return $this->_instances[$name];    
  }

}

class Some extends Manager{
  function f1(){
    $this->db->lol();
    $this->config->lol();
  }
}

$some=new Some();
$some->f1(); //echoes 'Hello from db->lol()' and 'Hello from config->lol()'

But for accessing global class instances I prefer using following method: Use singleton pattern to access global class trough GloballClass::i() and if global class is not defined use autoload to load that class.

class db extends mysqli{
  private static $_i;
  //Access to singleton instance
  public static function i()    {       
    return (self::$_i instanceof self)?self::$_i:self::$_i = new self();
  }

  //class functions
  function q($q){
    echo 'Hello from db->q()';
  } 
}

class config{
  private static $_i;
  //Access to singleton instance
  public static function i()    {       
    return (self::$_i instanceof self)?self::$_i:self::$_i = new self();
  }

  //class functions
  function somefunction(){
    echo 'Hello from config->somefunction()';
  } 
}


db::i()->q('SELECT * FROM users');
config::i()->somefunction();

Following is solution inspired by Gordons comment: It uses GlobalClassFactory class to define only one instance of global classes.

class db{
  function lol(){
    echo 'Hello from db->lol() <br />';
  }
}
class config{
  function lol(){
    echo 'Hello from config->lol() <br />';
  }
}

class GlobalClassFactory{
  private static $_classes=array();
  public static function getInstance($name){
    if (!isset(self::$_classes[$name])){
      self::$_classes[$name]=new $name();
    }
    return self::$_classes[$name];
  }
}

class Base{
  function __get($name){
    return GlobalClassFactory::getInstance($name);
  }
}

class Some extends Base{
  function f1(){
    $this->db->lol();
    $this->config->lol();
  }
}

$some=new Some();
$some->f1();


Here is the sample prototype:

include 'db.php'; // include db class
include 'config.php'; // include config class

class main{
  public $db = NULL;
  public $config = NULL;

  function __construct() {
    $this->db = new db;
    $this->config = new config;
  }

}


Creating a composite object with instances of everything that might be needed during code execution up front is a complete waste of resources. You want to create instances only when needed. One way to achieve this would be to add a magic __get method to the class:

public function __get($name) {
    // if self::$instances (or main) contains instance of $name, return instance
    // else if class_exists $name, create, store and return instance
    // else throw exception
}

But even then, chances are you are creating a God Object and magic methods are somewhat slower than regular accessors. If you need to create instances this way, have a look at the Symfony Dependency Injection Container or implement a Registry.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜