2009-03-13 12 views
29

Estoy tratando de realizar algún tipo de función que cargue y ejemplifique una clase a partir de una variable determinada. Algo como esto:¿Cómo puedo llamar a un método estático en una clase variable?

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

Si lo uso como esto:

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

Debe incluir y crear instancias de la clase de sesión.

Por cierto: la función getInstance estática viene de este código:

<?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]; 
    } 

    } 

?> 

Lo que pasa es que en este momento la manera de utilizar las funciones de una clase es la siguiente:

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

Pero ahora quiero construir eso en una función para que nunca más tenga que usar esa línea de código. Acabo de decir loadClass ('session'); y que puedo usar $ session-> blablablafunction();

Respuesta

36

Puede utilizar call_user_func():

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

El primer argumento es un tipo callback que contiene el nombre de la clase y el nombre del método en este caso.

0

Parece que estás luchando contra la unión estática de implementación actual de PHP, que es la razón por la que estás saltando a través de aros con getCallingClass. Puedo decirte por experiencia que probablemente deberías dejar de tratar de crear instancias en una clase para padres a través de un método estático. Te causará más problemas al final. PHP 5.3 implementará "late static binding" y debería resolver su problema, pero obviamente eso no ayuda ahora.

Probablemente sea mejor que utilice la funcionalidad de carga automática mencionada por kodisha combinada con una implementación de Singleton sólida. No estoy seguro de si su objetivo es el azúcar sintáctico o no, pero cree que lo hará mejor a largo plazo para evitar algunos personajes.

0

De la parte superior de la cabeza, las necesidades de pruebas, etc validación:

<?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

Llamando funciones estáticas en un nombre de clase variable es aparentemente disponible en PHP 5.3:

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

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

Definitivamente podría usar eso ahora mismo.

Hasta entonces, no se puede suponer que todas las clases que esté cargando estén diseñadas para ser singleton. Siempre que use < 5.3 que tendrá que acaba de cargar la clase y la instancia a través del constructor:

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

}

O

sólo tiene que cargar la clase sin crear un objeto de la misma. A continuación, llame a ":: getInstance()" en aquellos destinados a ser singletons, y "nuevo" en los que no lo son, desde fuera de la función loadClass().

Aunque, como otros han señalado anteriormente, una __autoload() probablemente funcione bien para usted.

0

Los enlaces estáticos finales funcionarán para usted, creo. En la construcción de cada clase do:

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

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

Entonces ... Aquí es un cargador automático que he creado. Vea si esto resuelve su dilema.

// 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; 
} 

Entonces todo lo que tiene que hacer es

$var = new ClassName(); 

pero hay que tener un archivo php en la ruta con el nombre ClassName.php donde NombredeClase es el mismo que el nombre de la clase que quiere crear una instancia.

Cuestiones relacionadas