views:

1163

answers:

6

Hi,

I'm trying to make some kind of function that loads and instantiates a class from a given variable. Something like this:

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

If I use it like this:

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

It should include and instantiate the session class.

BTW: the static getInstance function comes from this 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];
    }

  }

?>

I'm kinda lost (I even tried to use eval :P). Can someone help me. You'll put a big smile on my face.

Thanks in advance...

+5  A: 

You can use call_user_func():

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

The first argument is a callback type containing the classname and method name in this case.

Greg
+2  A: 

Why not use __autoload() function?

http://www.php.net/autoload

then you just instantiate object when needed.

kodisha
A: 

The thing is that right now the way to use the functions in a class is this:

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

But now I want to build that into a function so that I never again have to use that line of code. I just say loadClass('session'); and than I can use $session->blablablafunction();

This doesn't address the question of calling a method on a variable class.
Sam
+1  A: 

It looks like you are fighting PHP's current implementation static binding, which is why you are jumping through hoops with getCallingClass. I can tell you from experience, you should probably abandon trying to put instantiation in a parent class through a static method. It will cause you more problems in the end. PHP 5.3 will implement "late static binding" and should solve your problem, but that obviously doesn't help now.

You are probably better off using the autoload functionality mentioned by kodisha combined with a solid Singleton implementation. I'm not sure if your goal is syntactic sugar or not, but it think you will do better in the long run to steer clear of trying to save a few characters.

Barrett Conrad
A: 

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

?>
jcinacio
A: 

Calling static functions on a variable class name is apparently available in PHP 5.3:

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

http://www.phpbuilder.com/manual/language.oop5.static.php

Could definitely use that right now myself.

Until then you can't really assume that every class you are loading is designed to be a singleton. So long as you are using < 5.3 you'll have to just load the class and instantiate via the constructor:

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

}

OR

Just load the class without creating an object from it. Then call "::getInstance()" on those meant to be singletons, and "new" on those that are not, from outside of the loadClass() function.

Although, as others have pointed out earlier, an __autoload() would probably work well for you.

talentedmrjones