2009-03-13 12 views
29

Sto provando a creare una sorta di funzione che carica e crea un'istanza di una classe da una determinata variabile. Qualcosa di simile a questo:Come posso chiamare un metodo statico su una classe variabile?

<?php 
function loadClass($class) { 
    $sClassPath = SYSPATH."/classes/{$class}.php"; 
    if (file_exists($sClassPath)) { 
    require_once($sClassPath); 
    $class = $class::getInstance(); 
    } 
} 
?> 

Se lo uso così:

<?php 
    loadClass('session'); 
?> 

Esso dovrebbe includere e creare un'istanza della classe sessione.

BTW: la funzione getInstance statica viene da questo codice:

<?php 
    function getCallingClass() { 
    $backtrace = debug_backtrace(); 
    $method = $backtrace[1]['function']; 
    $file  = file($backtrace[1]['file']); 
    $line  = $file[($backtrace[1]['line'] - 1)]; 
    $class  = trim(preg_replace("/^.+?([A-Za-z0-9_]*)::{$method}\(.*$/s", "\\1\\2", $line)); 

    if(! class_exists($class)) { 
     return false; 
    } return $class; 
    } 

    class Core { 

    protected static $instances = array(); 

    public static function getInstance() { 
     $class = getCallingClass(); 

     if (!isset(self::$instances[$class])) { 
     self::$instances[$class] = new $class(); 
     } return self::$instances[$class]; 
    } 

    } 

?> 

Il fatto è che in questo momento il modo di utilizzare le funzioni in una classe è questa:

<?php 
    $session = session::getInstance(); 
?> 

Ma ora voglio costruirlo in una funzione in modo che non debba mai più usare quella riga di codice. Dico solo loadClass ('sessione'); e di quanto so usare $ session-> blablablafunction();

risposta

36

È possibile utilizzare call_user_func():

$class = call_user_func(array($class, 'getInstance')); 

Il primo argomento è un tipo callback contenente il nome di classe e nome del metodo in questo caso.

0

Sembra che tu stia combattendo il binding statico dell'attuale implementazione di PHP, motivo per cui stai saltando i cerchi con getCallingClass. Posso dirti per esperienza, dovresti probabilmente rinunciare a provare a mettere l'istanza in una classe genitore attraverso un metodo statico. Alla fine ti causerà più problemi. PHP 5.3 implementerà "late static binding" e dovrebbe risolvere il tuo problema, ma questo ovviamente non aiuta ora.

Probabilmente stai meglio usando la funzionalità di autoload menzionata da kodisha in combinazione con un'implementazione solida di Singleton. Non sono sicuro che il tuo obiettivo sia zucchero sintattico o meno, ma pensi che farai meglio a lungo termine per evitare di cercare di salvare alcuni personaggi.

0

Fuori della parte superiore della mia testa, ha bisogno di prove, ecc convalida:

<?php 

    function loadClass($className) { 
     if (is_object($GLOBALS[$className])) 
      return; 

     $sClassPath = SYSPATH."/classes/{$className}.php"; 
     if (file_exists($sClassPath)) { 
      require_once($sClassPath); 

      $reflect = new ReflectionClass($className); 
      $classObj = $reflect->newInstanceArgs(); 
      $GLOBALS[$className] = $classObj; 
     } 
    } 

?> 
36

Calling funzioni statiche su un nome di classe variabile è apparentemente disponibile in PHP 5.3:

Foo::aStaticMethod(); 
$classname = 'Foo'; 
$classname::aStaticMethod(); // As of PHP 5.3.0 

http://php.net/manual/en/language.oop5.static.php

Potrei sicuramente usarlo subito.

Fino ad allora non si può davvero supporre che ogni classe che si sta caricando sia progettata per essere un singleton. Finché si utilizza < 5.3 dovrete caricare solo la classe e istanziare tramite il costruttore:

function loadClass($class) { 
    $sClassPath = SYSPATH."/classes/{$class}.php"; 
    if (file_exists($sClassPath)) { 
    require_once($sClassPath); 
    $class = new $class; 
    } 

}

O

Basta caricare la classe senza creare un oggetto da esso. Quindi chiama ":: getInstance()" su quelli che devono essere singleton e "new" su quelli che non lo sono, dall'esterno della funzione loadClass().

Sebbene, come altri hanno sottolineato in precedenza, un __autoload() potrebbe funzionare bene per voi.

0

Le associazioni statiche tardive funzioneranno per voi, penso. Nel costrutto di ogni classe do:

class ClassName 
{ 
    public static $instances = array(); 

    public function __construct() 
    { 
     self::$instances[] = $this; 
    } 
} 

Poi ... Ecco un caricatore automatico che ho creato. Vedi se questo risolve il tuo dilemma.

// Shorten constants for convenience 
define ('DS', DIRECTORY_SEPARATOR); 
define ('PS', PATH_SEPARATOR); 
$template = "default"; 

// Define an application path constants 
define ('APP_ROOT', realpath('.').DS); 
define ('VIEW', APP_ROOT . 'Views' . DS); 
define ('MODEL', APP_ROOT . 'Models' . DS); 
define ('CONTROLLER', APP_ROOT . 'Controllers' . DS); 
define ('TEMPLATE', VIEW."templates".DS.$template.DS); 
define ('CONTENT', VIEW."content".DS); 
define ('HELPERS', MODEL."helpers".DS); 

// Check if application is in development stage and set error reporting and 
// logging accordingly 

error_reporting(E_ALL); 
if (defined('DEVELOPMENT')) { 
    ini_set('display_errors', 1); 
} else { 
    ini_set('display_errors', 0); 
    ini_set('log_errors', 'On'); 
    ini_set('error_log', APP_ROOT.'error.log'); 
} 

$paths = array(APP_ROOT, VIEW, MODEL, CONTROLLER, TEMPLATE, CONTENT, HELPERS); 

// Set the include path from Config Object 
set_include_path(implode(PS, $paths)); 

// Autoloader 
function __autoload($class) 
{ 
    require_once $class.'.php'; 
    return; 
} 

Poi tutto quello che dovete fare è

$var = new ClassName(); 

ma devi avere un file php nel percorso con il nome ClassName.php dove ClassName è lo stesso nome del classe che vuoi istanziare.