web-dev-qa-db-fra.com

Comment puis-je appeler une méthode statique sur une classe de variable?

J'essaie de créer une sorte de fonction qui charge et instancie une classe à partir d'une variable donnée. Quelque chose comme ça:

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

Si je l'utilise comme ça:

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

Il devrait inclure et instancier la classe de session.

BTW: la fonction statique getInstance provient de ce code:

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

  }

?>

Le truc, c'est qu'actuellement, la manière d'utiliser les fonctions d'une classe est la suivante:

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

Mais maintenant, je veux intégrer cela dans une fonction afin de ne plus jamais avoir à utiliser cette ligne de code . Je viens de dire loadClass ('session'); Et que je puisse utiliser $ session-> blablablafunction ( )

34
Jelle Spekken

L'appel de fonctions statiques sur un nom de classe de variable est apparemment disponible dans PHP 5.3:

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

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

Pourrait certainement utiliser cela maintenant moi-même.

Jusque-là, vous ne pouvez pas supposer que chaque classe que vous chargez est conçue pour être un singleton. Tant que vous utilisez <5.3, vous devrez simplement charger la classe et instancier via le constructeur:

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

}

OR

Il suffit de charger la classe sans en créer un objet. Appelez ensuite ":: getInstance ()" sur ceux qui sont destinés à être des singletons et "new" sur ceux qui ne le sont pas, en dehors de la fonction loadClass ().

Bien que, comme d’autres l’ont déjà fait remarquer, un __autoload () fonctionnerait probablement bien pour vous.

44
talentedmrjones

Vous pouvez utiliser call_user_func() :

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

Le premier argument est un callback type contenant le nom de classe et le nom de la méthode dans ce cas.

38
Greg

Pourquoi ne pas utiliser la fonction __autoload ()?

http://www.php.net/autoload

alors vous instanciez simplement un objet en cas de besoin.

2
kodisha

Les liaisons statiques tardives fonctionneront pour vous, je pense. Dans la construction de chaque classe, faites:

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

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

Ensuite, voici un autoloader que j'ai créé. Voyez si cela résout votre dilemme.

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

Ensuite, tout ce que vous avez à faire est

$var = new ClassName();

mais vous devez avoir un fichier php dans le chemin avec le nom ClassName.php Où ClassName est identique au nom de la classe à instancier.

0
Corey Ray

Il semble que vous combattiez la liaison statique de l'implémentation actuelle de PHP. C'est pourquoi vous sautez à travers des cerceaux avec getCallingClass. Je peux vous dire, d’expérience, que vous devriez probablement abandonner l’essai de placer l’instanciation dans une classe par le biais d’une méthode statique. Cela vous causera plus de problèmes à la fin. PHP 5.3 implémentera "dernière liaison statique" et devrait résoudre votre problème, mais cela n’aide évidemment pas pour le moment. 

Vous ferez probablement mieux d'utiliser la fonctionnalité de chargement automatique mentionnée par kodisha, associée à une implémentation solide de Singleton. Je ne suis pas sûr que votre objectif soit le sucre syntaxique ou non, mais il pense que vous ferez mieux à long terme pour éviter d'essayer de sauvegarder quelques caractères.

0
Barrett Conrad

De mémoire, j'ai besoin de tests, de validation, etc.:

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

?>
0
J.C. Inacio