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.
精彩评论