1) utilisent __autoload ou spl_autoload_register pour charger les classes
2) utiliser des méthodes magiques, pour appeler la fonction lors de l'obtention propriété inconnue. Les exemples suivants montrent comment utiliser __get et dynamicaly initialize object uniquement lorsque vous les utilisez.
//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()'
Mais pour accéder à des instances de classe mondiale, je préfère utiliser la méthode suivante: Utiliser modèle singleton pour accéder GloballClass global creux de classe :: i() et si la classe mondiale ne définit pas l'utilisation autoload pour charger cette classe.
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();
Suite est une solution inspirée par Gordons commentaire: Il utilise la classe GlobalClassFactory pour définir une seule instance de classes mondiales.
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();
La sous-classification d'une classe de base générale est presque toujours une mauvaise idée. Vous créez une relation qui dit 'Some' * is-a *' Manager', quand ce n'est vraiment pas le cas.De même, si vous stockez les instances en tant qu'instances d'objet, toute classe développant le gestionnaire créera des instances séparées uniquement pour lui-même, ce qui dans le cas de db et de config est peu probable. Les singletons peuvent atténuer cela, mais étant donné que Singletons ne peut pas être instancié avec 'new', le code dans' __get' ne fonctionnera plus. Et les Singletons sont généralement une mauvaise idée de toute façon. – Gordon
Vous avez raison, Gordon, j'ai donc créé une solution où une seule instance de chaque classe globale est créée. Mais pourquoi les Singletons sont une mauvaise idée? – codez
Vous venez d'échanger le problème :) Comment créez-vous non-Singleton maintenant? En outre, vous créez toujours une relation * is-a * et maintenant vous avez également couplé la classe Base à l'usine en la codant en dur dans la méthode '__get', réduisant ainsi efficacement la classe Base à un getter magique. Je veux dire, bien sûr que cela fonctionne, mais c'est une mauvaise conception IMO. Essayez d'éviter les choses * globales *. – Gordon