Creating objects with dynamic class names

Hi all,

consider the following situation:

I have a class name stored in the variable $className.

$className = 'class_that_does_something';

What I want to do is to create a class_that_does_something object.

$newInstance = new $className;

Well, obviously that doesn’t work :frowning:

Anyone can point me to a solution to this? Many thanks.

That method should work.

I just tried:


<?php
class Person {
    var $firstName;
    var $lastName;

    function Person($firstName = null, $lastName = null) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    function setFirstName($firstName) {
    	$this->firstName = $firstName;
    }

    function setLastName($lastName) {
    	$this->lastName = $lastName;
    }

    function getFirstName() {
    	return $this->firstName;
    }

    function getLastName() {
    	return $this->lastName;
    }
}

$className = "Person";
$theInstance = new $className;

$theInstance->setFirstName("John");
$theInstance->setLastName("Doe");

echo $theInstance->getFirstName() . " " . $theInstance->getLastName();
?>

and it works fine.

JT

Yer, it should work. Only problem I can see is if you want to pass on some parameters ? But you don’t say this for sure though :slight_smile:

What OS are you using btw ?

I co-wrote a Singleton class which allows the passing of parameters. (I say co-wrote because much of it is based on Haruki Setoyama’s Singleton class.)

The problem was the same. If you wanted to initialize an instantiated Singleton an extra method like init() had to be called after creating it. Something like…

class Singleton {
    function &getInstance() {
        static $instance;

        if(!isset($instance)) {
            $instance =& new SingletonObject;
            $instance->init($params_here);
        }
        return $instance;
    }
}

This really only allows one type of object to be created using this Singleton method.

I wanted to create a Singleton method which allows any object to be instantiated as a singleton without having to give many objects a getInstance() method. My solution uses plenty of eval()s, which will offend some people, but I don’t think there’s a risk with this. Here’s what I did:

<?php
/**
*   Singleton.php
*   Class adapted from Haruki Setoyama's Singleton class
*   $Id: singleton.php,v 1.1 2003/06/02 22:11:28 haruki Exp $
*   @author     Haruki Setoyama, David Rodger
*   @access public
*/

class Singleton {

    /**
    *   Last error message
    *   @access private
    *   @var    string
    **/
    var $error;

    /**
    *   Singletons created
    *   @access private
    *   @var    array
    **/
    var $instances;

    /**
    *   Constructor. Does nothing except initialize instances array.
    *   @access private
    *   @return void
    **/
    function Singleton() {
        $this->instances = array();
    }

    /**
    *   Fetch error message
    *   @access public
    *   @return string  Error message
    **/
    function getError() {
        return $this->error;
    }

    /**
    *   Alias of self
    *   @access public
    *   @return Singleton
    **/
    function init() {
        Singleton::self();
    }
    /**
    *   Get an instance of the Singleton class, required so that object duplication
    *   cannot occur.
    *   @access public
    *   @return Singleton
    **/
    function &self() {
        static $singleton_object;

        if(!isset($singleton_object)) {
            $singleton_object = new Singleton();
        }
        return $singleton_object;
    }
    /**
    *   Checks for an instance of the Singleton class and then returns an instance of the
    *   class named by $classname. See instance() method for more details.
    *   @access public
    *   @param  string  Name of the class
    *   @param  string  Directory path of class definition
    *   @return object  Instance of class
    */
    function &getInstance($classname = 'Singleton', $params = array()) {
        static $singleton;

        if(!isset($singleton)) {
            $singleton =& Singleton::self();
        }
        if($classname == 'Singleton') {
            return $singleton;
        } else {
            return $singleton->instance($classname, $params);
        }
    }

    /**
    *   Returns an instance of the named class. Such classes must have constructors
    *   which expect no arguments. Class files must be include()-ed before calling this.
    *   @access public
    *   @param  string  Name of the class
    *   @param  array   Parameters to be passed to the constructor method of the class
    *   @return object  Instance of class
    */
    function &instance($classname, $params = array()) {
        if(!isset($this->instances[$classname])) {
            if(!class_exists($classname)) {
                $this->error = "Singleton::instance(): Class <b>".$classname."</b> does not exist.";
                return FALSE;
            } else {
                $this->createClass($classname, $params);
            }
        }
        return $this->instances[$classname];
    }

    /**
    *   Creates the class to be instantiated, with parameters, and adds it to the
    *   singleton's instances array.
    *   Parameters must be passed as an associative array whose key is the name used
    *   for the passed variable inside the class's constuctor method.
    *   @access private
    *   @param  string  Name of the class
    *   @param  array   Parameters to be passed to the constructor method of the class
    *   @return void
    */
    function createClass($classname, $params) {
        $passedVars = array();
        foreach($params as $key => $value) {
            switch(gettype($value)) {
                case "object":
                    eval("\\$".$key." =& \\$params['".$key."'];");
                    break;
                case "string":
                    eval("\\$".$key." = '".$value."';");
                    break;
                default:
                    eval("\\$".$key." = ".$value.";");
                    break;
            }
            $passedVars[] = "$".$key;
        }
        $passedVars = implode(", ", $passedVars);
        eval("\\$this->instances[\\$classname] =& new \\$classname(".$passedVars.");");
    }

}

?>

In your case, you could write an ObjectFactory class whose getInstance() method does not store the instance as a static variable, but which can create an instance with parameters passed, much the same way as my Singleton::createClass() method.

Hope this helps,
David


<?php
class Person {
    var $firstName;
    var $lastName;

    function Person($firstName = null, $lastName = null) {
        $this->firstName = $firstName;
        $this->lastName = $lastName;
    }

    function setFirstName($firstName) {
    	$this->firstName = $firstName;
    }

    function setLastName($lastName) {
    	$this->lastName = $lastName;
    }

    function getFirstName() {
    	return $this->firstName;
    }

    function getLastName() {
    	return $this->lastName;
    }
}

$className = "Person";
//$theInstance = new $className;
$thisInstance = new $className("John", "Doe");

//$theInstance->setFirstName("John");
//$theInstance->setLastName("Doe");

echo $theInstance->getFirstName() . " " . $theInstance->getLastName();
?>

You can still pass parameters with my example.

JT

The two main limitations on using class names stored in a variable, that I’ve found, are;

String interpolation not allowed


$class_prefix = 'XML_';
$class = 'Parser';

// NOT ALLOWED
$object =&  new $class_prefix . $class();

// ALLOWED
$class_full_name = $class_prefix . $class;
$object =&  new $class_full_name();

Not too critical - just means an extra line of code to interpolate beforehand.

The other one is the static method call syntax;


class Foo {
    function test() {
         echo "Testing";
    }
}

$class = "Foo";

// NOT ALLOWED
$class::test();

There’s been the odd occasion where I’ve cursed not having that but it’s rare.

Could be there’s workarounds for these I haven’t found.

1 Like

// NOT ALLOWED
$class::test();

// ALLOWED
call_user_func(array($class,'test'));

Hi synth…

Why do you need to create an object given the name of a class?

yours, Marcus

There’s been the odd occasion where I’ve cursed not having that but it’s rare.

:agree:

Hi all,

must be something i’ve missed. Let me go check out my code again.

Marcus, just an experiment…

Thank-you!!! This works brilliantly for me! And you can just pass in parameters as subsequent arguments to call_user_func().

I use something like this to call a static method to return a singleton for a class.


  $object = & call_user_func(array($class,'getInstance'), $param1, $param2 );