42

我正在尝试制作某种从给定变量加载和实例化类的函数。像这样的东西:

<?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'); 而且我可以使用 $session->blablablafunction();

4

6 回答 6

54

在变量类名上调用静态函数显然在 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,您就必须加载类并通过构造函数进行实例化:

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

}

或者

只需加载类而不从中创建对象。然后从 loadClass() 函数之外对那些意味着单例的调用“::getInstance()”,对那些不是单例的调用“new”。

尽管正如其他人之前指出的那样, __autoload() 可能对您很有效。

于 2010-06-25T21:27:03.980 回答
38

您可以使用call_user_func()

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

在这种情况下,第一个参数是callback包含类名和方法名的类型。

于 2009-03-13T12:16:46.043 回答
2

为什么不使用 __autoload() 函数?

http://www.php.net/autoload

然后您只需在需要时实例化对象。

于 2009-03-13T12:18:36.177 回答
0

Off the top of my head, needs testing, 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;
        }
    }

?>
于 2009-03-13T18:19:34.733 回答
0

看起来您正在与 PHP 的当前实现静态绑定作斗争,这就是您使用 getCallingClass 跳过箍的原因。我可以根据经验告诉你,你可能应该放弃尝试通过静态方法将实例化放在父类中。它最终会给你带来更多的问题。PHP 5.3 将实现“后期静态绑定”并且应该可以解决您的问题,但现在显然没有帮助。

您可能最好使用 kodisha 提到的自动加载功能并结合可靠的 Singleton 实现。我不确定你的目标是否是语法糖,但它认为从长远来看你会做得更好,以避免试图保存几个字符。

于 2009-03-13T14:10:23.633 回答
0

我认为后期静态绑定对你有用。在每个类的构造中执行:

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();

但是您必须在路径中有一个名为 ClassName.php 的 php 文件,其中 ClassName 与您要实例化的类的名称相同。

于 2013-07-26T16:16:27.270 回答