Dynamic invocation of constructors...

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

timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

With runkit_method_add it becomes possible to add a 'custom' method to a class.. And you could update the properties in that custom method...

Here is an example where i add a constructor that accepts an associative array with property, value pairs.

Code: Select all

<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', TRUE);

class Foo {
	public function getName() {
		return $this->name;
	}
}

runkit_method_add(
	'Foo', 
	'__construct', 
	'$args',
	'foreach($args as $key => $val) { $this->$key =$val; }'
);

$foo = new Foo(array('name' => 'john', 'age' => 26));
print $foo->getName();
?>
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Now that's interesting ... Has there been any benchmarking on the efficiency of the runkit? As long as its "minimal" compared to a database connection/overhead this might work.

Hmm but the runkit appears to knock out the old constructor (which makes sense as PHP doesn't have real method overloading), so I'ld need to capture the old signature and body of the constructor and then restore it after the ORM creates the needed class. As its highly likely that after loading the object tree its likely that the application will need to instantiate "normal" instances of the class.
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

You could first runkit_method_rename __construct to a tmpname...
Add your custom constructor and initialize the objects you need..
Finally runkit_method_rename tmpname to __construct

(Haven't had the time to checkout performance issues etc of the runkit...)
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

yeah that's exactly what I was just playing with...
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

The problem with runkit is it is not installed by default as I recall..

You might want to have runkit_method_rename __construct to something like __original_construct. Then add your own constructor and have the injected constructor call __original_construct().
(#10850)
User avatar
nielsene
DevNet Resident
Posts: 1834
Joined: Fri Aug 16, 2002 8:57 am
Location: Watertown, MA

Post by nielsene »

Yeah, seeing how the body of the constructor is not always as simple as direct key/value assignments. A variety of minor processing is often done to convert inputs to canonical forms, etc.

renaming the old constructor and then using the call_user_func_array from within the dynamic generated constructor would work. While for my own use I'm willing to have the reliance on the runkit, if I decide to go that route,. I'd not be willing to make that a requirement should I try to bundle/release the ORM layer, though, so I think I'll have to stick with eval for now, as interesting/nice as the runkit approach is looking.
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post by alex.barylski »

In which case use eval()

Whats so unsecure about the following code?

Code: Select all

class Contacts{
    function __construct($name, $title, $email)
    {
      $this->name = $name;
      $this->title = $title;
      $this->email = $email;
    }

    private $name;
    private $title;
    private $email;
  }

  $arg = array('"Alex"', '"Coordinator"', '"nuweb1@hotmail.com"');

  $cls = 'Contacts';
  eval('$obj = new '.$cls.'('.(implode(', ', $arg)).');');

  print_r( $obj );
You could call preg_match() on $cls and/or use some convention which only your ORM objects are likely to follow (prevent incorrect object instantiation) and follow the same process for $arg...

All in all relatively easy...fairly straight forward and does what you are asking...I think... :roll:

I'd go with eval() as it's your only option...or at least guaranteed to work on any version of PHP...

Or you can go with arrays as parameter lists and use the dreaded get_func_args() type functions and then inside the function call extract()?

Cheers :)
alex.barylski
DevNet Evangelist
Posts: 6267
Joined: Tue Dec 21, 2004 5:00 pm
Location: Winnipeg

Post by alex.barylski »

arborint wrote:From what I can tell, the reason that you still have to do stuff like this is because the PHP core group have what I would consider an old fashioned view of OO. And unfortunately, there are really no plans for much improvement in the PHP object model because of this attitude. There are a number of features that, though they would rarely be used by application programmers, would help library builders create really interesting stuff in PHP.
Just curious, but how do you mean old fashioned?

How is this issue solved in other languages?

Cheers :)
Post Reply