Dynamic invocation of constructors...
Moderator: General Moderators
Dynamic invocation of constructors...
I'm running into a situation where I need dynamic invocation of a constructor with an unkown number of arguments.
That is I don't know either the class name or the arugment list at script-writing time. (I would say compile time, but....)
Normally I use call_user_func_array() for this, but it appears that it doesn't work with constructor type functions. There's always eval, but I would prefer to avoid that. Is there any other workaround?
If I knew the argument list at script writing time, I could just do a "new $classname($arg1, $arg2,...)" However, I need the rich constructor and can't fallback to a no-args constructor and lots of setFoo calls.
That is I don't know either the class name or the arugment list at script-writing time. (I would say compile time, but....)
Normally I use call_user_func_array() for this, but it appears that it doesn't work with constructor type functions. There's always eval, but I would prefer to avoid that. Is there any other workaround?
If I knew the argument list at script writing time, I could just do a "new $classname($arg1, $arg2,...)" However, I need the rich constructor and can't fallback to a no-args constructor and lots of setFoo calls.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
As much as I dislike the site, the tenor, the members, and the overall environment, these questions I find are often better answered at Sitepoint's php forums. Perhaps try asking there.nielsene wrote:I know those patterns; they don't apply here.
I give up. As always, it seems I can't ask questions that lead to answers.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
I think you need to describe it better then. It almost sounds like you need something like the WACT Handle class that resolves classes. You haven't said what the purpose is. Lazy Load, Virtualize?nielsene wrote:I know those patterns; they don't apply here.
I give up. As always, it seems I can't ask questions that lead to answers.
You started out saying "with an unkown number of arguments", then you said "The different classes don't take variable arguments." If you talk through the problem you may discover, for yourself, whether you should be solving it in this way or not. I am certainly not clear what you are trying to do.
(#10850)
OK I'll try again, but I don't expect it to help, since people will just say my approach is wrong.
In the middle of my ORM layer, I often need to instantiate a class that requires a rich constructor. The mapping files identifies the class needed and a "template" constructor argument list. Thus I can build the argument list that the chosen constructor needs. However short of eval, I can't seem to find anyway to call the constructor with the appropriate arguments.
Different classes being loaded by the ORM might need different number of arguments, thus I can't do something like "new $foo($arg1, $arg2, $arg3)";
In this case the object being loaded is immutable and I have to create it from the rich constructor, thus no JavaBean style convention of a no-args constructor followed by lots of setX calls. The ORM layer is designed to impose NO requirements on the classe to be persisted -- it does require a more complicated mapping syntax, but it doesn't corrupt the domain model.
Basically I need a
However call_user_func can't be used to invoke a constructor according to the documentation (and confirmed by trying it anyways.)
In the middle of my ORM layer, I often need to instantiate a class that requires a rich constructor. The mapping files identifies the class needed and a "template" constructor argument list. Thus I can build the argument list that the chosen constructor needs. However short of eval, I can't seem to find anyway to call the constructor with the appropriate arguments.
Different classes being loaded by the ORM might need different number of arguments, thus I can't do something like "new $foo($arg1, $arg2, $arg3)";
In this case the object being loaded is immutable and I have to create it from the rich constructor, thus no JavaBean style convention of a no-args constructor followed by lots of setX calls. The ORM layer is designed to impose NO requirements on the classe to be persisted -- it does require a more complicated mapping syntax, but it doesn't corrupt the domain model.
Basically I need a
Code: Select all
$obj = call_user_func(array($className,'__construct'),$args);- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
It sound like you need eval(). There is nothing wrong with resorting to eval() when needed. Here is some lastcraft code from his changes library that may be inspiration:
Code: Select all
<?php
/**
* $Id: invoker_class.php,v 1.8 2004/11/09 17:32:36 marcusbaker Exp $
* Calls an object method with reference parameters and returns the
* result by reference. Replaces call_user_func_array().
* @copyright http://www.wordtracker.com (Rivergold Associates Ltd)
* @author Mike Mindel & Marcus Baker & Peter Brown
* @package classes
*/
/** @ignore */
/**
* This class is currently just a method to call other objects with the
* parameters as an array.
* @package classes
*/
class Invoker {
/**
* Service.
* @access public
* @param array $parameters Reference passed array of parameters.
*/
function Invoker() {
}
/**
* Calls an object and passes the array of parameters by reference.
* @access public
* @param object $object Object to call on.
* @param string $method Method name.
* @param array $parameters Array of parameters passed by reference.
* @return mixed Reference return of method result.
*/
function &invokeMethod(&$object, $method, &$parameters) {
$aliases = array();
for ($i = 0; $i < count($parameters); $i++) {
$aliases[] = "\$parameters[$i]";
}
$code = '$result = &$object->' . $method . '(' . implode(', ', $aliases) . ');';
eval($code);
return $result;
}
/**
* Calls a static method and passes the array of parameters by reference.
* @access public
* @param string $class Class to call on.
* @param string $method Method name.
* @param array $parameters Array of parameters passed by reference.
* @return mixed Reference return of method result.
*/
function &invokeStaticMethod($class, $method, &$parameters) {
$aliases = array();
for ($i = 0; $i < count($parameters); $i++) {
$aliases[] = "\$parameters[$i]";
}
$code = '$result = &' . $class . '::' . $method . '(' . implode(', ', $aliases) . ');';
eval($code);
return $result;
}
}
?>(#10850)
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
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.
(#10850)
I'm no expert at it yet, but I do believe using PHP4, you've hit a raod block on this. Except if you go with arborint's suggestion, by using the factory patterns available in most PEAR packages. Cue, PHP5. I know from my initial experiences with PHP5 you can use the get_/set_ methods in conjunction. There's a great little tute on it here. I hope that helps. Let me know what you find.
- Christopher
- Site Administrator
- Posts: 13596
- Joined: Wed Aug 25, 2004 7:54 pm
- Location: New York, NY, US
The problem with __get()/__set() is that they are error handlers -- not actually accessor functions. They are another example of problem library builders have with PHP. You really can't build things like an ORM layer that will "impose NO requirements on the classe to be persisted" as nielsene is finding. I have seen some of the best PHP programmers hit this wall ... even Zend failed with their own attempt at an Active Record implementation for the Zend Framework. It is a lack of vision that causes us all to suffer from a lack of high-powered libraries (things like Hibernate) in PHP.
(#10850)
-
alex.barylski
- DevNet Evangelist
- Posts: 6267
- Joined: Tue Dec 21, 2004 5:00 pm
- Location: Winnipeg
For what reason would that be?Roja wrote:As much as I dislike the site, the tenor, the members, and the overall environment, these questions I find are often better answered at Sitepoint's php forums. Perhaps try asking there.nielsene wrote:I know those patterns; they don't apply here.
I give up. As always, it seems I can't ask questions that lead to answers.
Whats wrong with this place?
What reason would what be? That I dislike the site, the tenor, the members, and the overall environment at Sitepoint? Answering that would take the thread very very off-topic.Hockey wrote:For what reason would that be?Roja wrote:As much as I dislike the site, the tenor, the members, and the overall environment, these questions I find are often better answered at Sitepoint's php forums. Perhaps try asking there.nielsene wrote:I know those patterns; they don't apply here.
I give up. As always, it seems I can't ask questions that lead to answers.
Whats wrong with this place?
There is nothing wrong with this place. My point was that despite my dislike for Sitepoint, I find that the answers to OOP questions there are generally more robust than they are here.