Как я могу вызвать статический метод в классе переменной? - PullRequest
37 голосов
/ 13 марта 2009

Я пытаюсь создать какую-то функцию, которая загружает и создает экземпляр класса из заданной переменной. Примерно так:

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

Если я использую это так:

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

Он должен включать и создавать экземпляр класса сеанса.

Кстати: статическая функция getInstance происходит из этого кода:

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

  }

?>

Дело в том, что сейчас способ использования функций в классе таков:

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

Но теперь я хочу встроить это в функцию, чтобы мне больше никогда не приходилось использовать эту строку кода. Я просто говорю loadClass ('сессия'); и чем я могу использовать $ session-> blablablafunction ();

Ответы [ 6 ]

46 голосов
/ 26 июня 2010

Вызов статических функций для имени класса переменной, по-видимому, доступен в PHP 5.3:

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

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

Определенно мог бы использовать это прямо сейчас.

До этого вы не могли предполагать, что каждый загружаемый вами класс предназначен для использования в качестве одиночного. Пока вы используете <5.3, вам нужно будет просто загрузить класс и создать его экземпляр с помощью конструктора: </p>

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

}

OR

Просто загрузите класс, не создавая из него объект. Затем вызовите ":: getInstance ()" для тех, которые должны быть синглетонами, и "new" для тех, которые не являются извне функции loadClass ().

Хотя, как уже указывали другие, __autoload (), вероятно, будет хорошо работать для вас.

38 голосов
/ 13 марта 2009

Вы можете использовать call_user_func():

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

Первый аргумент - это тип callback, содержащий имя класса и имя метода в этом случае.

2 голосов
/ 13 марта 2009

Почему бы не использовать функцию __autoload ()?

http://www.php.net/autoload

тогда вы просто создаете объект при необходимости.

0 голосов
/ 26 июля 2013

Поздние статические привязки будут работать на вас, я думаю. В конструкции каждого класса сделать:

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

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

Тогда ... Вот автозагрузчик, который я создал. Посмотрите, решит ли это вашу дилемму.

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

Тогда все, что вам нужно сделать, это

$var = new ClassName();

но у вас должен быть php файл в пути с именем ClassName.php где ClassName совпадает с именем класса, который вы хотите создать.

0 голосов
/ 13 марта 2009

Вне моей головы, нуждается в тестировании, проверке и т. Д .:

<?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 голосов
/ 13 марта 2009

Похоже, вы боретесь со статическим связыванием текущей реализации PHP, поэтому вы перепрыгиваете через getCallingClass. По опыту могу сказать, что вам, вероятно, следует отказаться от попыток поместить экземпляр в родительский класс с помощью статического метода. Это вызовет у вас больше проблем в конце. В PHP 5.3 будет реализовано «позднее статическое связывание» , и это должно решить вашу проблему, но это, очевидно, не помогает.

Возможно, вам лучше использовать функцию автозагрузки, упомянутую kodisha, в сочетании с солидной реализацией Singleton. Я не уверен, является ли ваша цель синтаксическим сахаром или нет, но думаю, что в конечном итоге вы добьетесь большего успеха, чтобы избежать попыток спасти несколько символов.

...