Dynamic object instantiation -- oh joy!

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

User avatar
neophyte
DevNet Resident
Posts: 1537
Joined: Tue Jan 20, 2004 4:58 pm
Location: Minnesota

Dynamic object instantiation -- oh joy!

Post by neophyte »

Code: Select all

public  function load_obj( $class, $handle, $args = null){
             if(class_exists($class)){
		  $obj = $$handle = new $class;
	     }
		$this->set_obj( $obj, $handle );
	}
I'm trying to write a method that dynamically instantiates a class.

This little bit I wrote works. It creates an object. But what I haven't been able to get work is adding $args to $class for constructor arguments. I'm not sure how this is done. Every string solution I've tried has failed. (I've tried making args an array and implode it to a string.) Any ideas?

Tanks!
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

Factory and/or Service Locator Pattern. :)

This thread will be of use: viewtopic.php?t=51794
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

ReflectionClass can do it

Code: Select all

<?php
class foo {
	public function __construct($a, $b) {
		echo $a, ' : ', $b;
	}
}


$args = array(3, 'a');

$rc = new ReflectionClass('foo');
$obj = $constructor = $rc->newInstanceArgs($args);
var_dump($obj);
?>
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Dynamic object instantiation -- oh joy!

Post by Christopher »

I believe this works:

Code: Select all

$obj = new $class($args);
You can use eval or reflection otherwise.
(#10850)
User avatar
neophyte
DevNet Resident
Posts: 1537
Joined: Tue Jan 20, 2004 4:58 pm
Location: Minnesota

Post by neophyte »

Jenk wrote:Factory and/or Service Locator Pattern. :)This thread will be of use: viewtopic.php?t=5179
Okay I read the thread and I have one thing I'm not sure about. Why was this chosen over

Code: Select all

eval("\$this->instances['$name'] =& new {$name}(" . implode(', ', $arglist) . ');');

this method?

Code: Select all

$this->instances[$name] = new $name($this->args[$name]);
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

The eval method allows any number of args. Usually $arglist is built from args from the variable arg functions. The second only allows one arg.

Note - There is a loop before the eval() that builds the $arglist.
(#10850)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

<-- still looking for a way to not use eval

EDIT: Oh and I actually don't even use that class now :lol:
But instead I have turned that class into an abstract class and subclassed registries for more specific tasks.... (request, session, etc) and then I use __autoload in combination with pear naming to load the classes. Works well :D
User avatar
neophyte
DevNet Resident
Posts: 1537
Joined: Tue Jan 20, 2004 4:58 pm
Location: Minnesota

Post by neophyte »

arborint wrote:The eval method allows any number of args. Usually $arglist is built from args from the variable arg functions. The second only allows one arg.
Note - There is a loop before the eval() that builds the $arglist.
Just discovered that one for myself. It must be the comma that is not evaluated as code but as a string.

Thanks to you and the Space Goat for exploring this pattern to the hilt. I think I've found most of what I was looking for.

And yes __autoload for PHP 5 is the way to go for inclusion -- it being triggered by class_exists()
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

just use include_once/require_once within __autoload()
User avatar
neophyte
DevNet Resident
Posts: 1537
Joined: Tue Jan 20, 2004 4:58 pm
Location: Minnesota

Post by neophyte »

Here's what I got so far... Feel free to comment.

Code: Select all

class gg_registry{
	private $stack;
	/**
	* Everything needed to instantiate the requested class
	* Thanks to "The Ninja Space Goat" and "Aborint" at
	* devnetwork for their help on this method.
	*	
	* @static
	* @param $class The name of the class to instantiate
	* @param $handle The name of the object
	* @param array $args an array of arguments to pass to the constructor
	*/
	 public function load_obj($class, $handle, array $args) { 
         $argslist = array();
         if(class_exists($class)){
		       if( empty($args) ){
		    			$obj = $$handle = new $class;	
		        } else {
		        	//Arguments to process
		        	$n = count($args); 
                 	for ($i=0; $i<$n; ++$i) { 
                         $arglist[$i] = "\$args[$i]"; 
                 	} 
                 	 eval ("$" . "object = new {$class}(" . implode(', ', $arglist) . ');'); 
		        }        
         }       
         $this->set_obj( &$object, $handle);
     } 
	/**
	 * This function is used for retrieving the registry obj in
	 * preparation for accessing objects it holds.
	 * 
	 * @return object returns a registry object
	 */
	public static function &instance(){
		static $reg;
		if (!$reg){
				$reg = new gg_registry;
		}
		return $reg;
	}
	/**
	* Adds objects and variables to the stack. Use if the object is already
	* instantiated. Works great for data objects or when load_obj for whatever
	* reason doesn't yield desirable results.
	*
	* @access public
	* @param object $object the object to be inserteregistry_test.phpd into the $GLOBALS container
	* @param string $handle optional name of class to be made globally accessible
	*/	
	public  function set_obj( &$object, $handle = '' ){
		$class = (empty($handle))? get_class($object): $handle;
		$this->stack[$class] = $object;
	}
	/**
	* A "getter" for retrieving objects from the registry.
	*
	* @access public
	* @param string $handle The name of the class to retrieve from the $GLOBALS array or the handle for the variable
	*/
	public function &get_obj($handle){
		return $this->stack[$handle];
	}
} // end class

/**
 * Automatically includes code for requested class
 * 
 * @param string $classname
 */
function __autoload($classname){
	if(strstr($classname, 'module')){
		$path = $_SERVER['DOCUMENT_ROOT'].'modules/';
	} else {
	    $path = $_SERVER['DOCUMENT_ROOT'].'lib/';
	}
	$ext = ".php";
	 $classname = substr_replace( $classname, '',0,3);
	include_once($path.$classname.$ext);
}
User avatar
Jenk
DevNet Master
Posts: 3587
Joined: Mon Sep 19, 2005 6:24 am
Location: London

Post by Jenk »

Have a look in this thread re: use of eval() for args:

viewtopic.php?t=53274
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

:D I believe that's the first time anybody has ever credited me in any type of code or even acknowledged me as a programmer. :D
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Jenk wrote:Have a look in this thread re: use of eval() for args:

viewtopic.php?t=53274
We started a thread around there to take a Registry to the next level and turn it into a Service Locator. I made a list of requirements. If we could come up with a Service Locator then Dependency Injection is just around the corner.
(#10850)
User avatar
daedalus__
DevNet Resident
Posts: 1925
Joined: Thu Feb 09, 2006 4:52 pm

Post by daedalus__ »

Are you using php4?
volka wrote:ReflectionClass can do it

Code: Select all

<?php
$rc = new ReflectionClass('foo');
$obj = $rc->newInstanceArgs($args);
?>
User avatar
volka
DevNet Evangelist
Posts: 8391
Joined: Tue May 07, 2002 9:48 am
Location: Berlin, ger

Post by volka »

Not the freshest thread, is it? ;)
Daedalus- wrote:Are you using php4?
Who's addressed by this question?
Post Reply