Solved

Better way to dynamically load instance w/ args

Posted on 2011-02-14
11
235 Views
Last Modified: 2013-12-13
I have a abstract class which has a getinstance function in. The problem I have is with arguments. Right now I am using an eval to pass those arguments to the class constructor. Is there a better way to do this.

See there HERE! part:
abstract class Core {
        /**
         * Arry of the class instances
         *
         * @var array
         */
        static protected $_instances = array();

        /**
         * Retrieves the singleton instance of this class.
         * This is completely self loading
         *
         * @return instance of this class
         */
        static public function getInstance() {
                //Get the called class so we know which class to load
                $class = get_called_class();

                //If there is not an already loaded instance
                if (!isset(self::$_instances[$class])) {
                        //If there were no passed in arguments
                        if (func_num_args() == 0) {
                                //Make the new class instance
                                self::$_instances[$class] = new $class();
                        } else {
                                //--------------- HERE! ------------------
                                $args = func_get_args();
                                $eval = 'self::$_instances[$class] = new $class(';
                                for ($i = 0, $count = func_num_args(); $i < $count; ++$i) {
                                        $eval .= '$args['.$i.'],';
                                }
                                $eval = substr($eval, 0, -1);
                                $eval .= ');';

                                eval($eval);
                        }
                }

                return self::$_instances[$class];
        }
}

Open in new window

0
Comment
Question by:Bryan_Heath
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 2
  • 2
  • +1
11 Comments
 
LVL 17

Expert Comment

by:Dushan De Silva
ID: 34894361
I think you should put  eval($eval) inside the loop, because this code will evaluate as php code and create new instance of only the last argument as the class name on the end of the loop. Are you using any common framework or in house build one?

0
 
LVL 1

Author Comment

by:Bryan_Heath
ID: 34897875
I don't understand your comment as that's not the case.  It will evaluate the to php code creating a new class passing in all the arguments.  For example:

class Test extends Core {
        public function __construct($foo, $bar) {
        }
}

$test = Test::getInstance('foo', 'bar');

Open in new window

This example will work because the $eval will be:
self::$_instances[$class] = new $class($arg[0], $arg[1]);

Open in new window

So it works perfectly fine and not my question.  

My question was is there a better way to do this since this seems sort of hackish.  Using eval always makes me nervous.
0
 
LVL 1

Author Comment

by:Bryan_Heath
ID: 34897893
Oh and this is in house framework
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 34

Accepted Solution

by:
Slick812 earned 500 total points
ID: 34898566
greetings Bryan_Heath, as you, "Using eval always makes me nervous" is also true for me.

As I looked at your code, you might consider changing your constructor to use an array for the parameters, which would give you a way to have any length of parameters,

function __construct($InArray=null){if ($InArray == null) {//code here to have it work when called  $x = new $class();
    }
}

And, you might could use -

$args = func_get_args()
self::$_instances[$class] = new $class($args);


A method I have used several times when I needed to call a function with some sort of "manipulated" arguments , was to use the  call_user_func ( )
   manual at  http://www.php.net/manual/en/function.call-user-func.php

the call_user_func ( ) worked well for me, however, I never tried it on a class "Static" function call.

I tried the forward_static_call( ) once, but I did not use it as it was to restrictive for what I needed to do, although it is meant for "Static" functions, maybe it just calls a parent class static function, from a subclass, I am not sure, but you might look at it.
0
 
LVL 1

Author Comment

by:Bryan_Heath
ID: 34898839
I thought of using an array but I was trying to keep the constructor clean as this will be the core of 99% of the classes I will be using.  Though a possibility I want to not do that if I can.

However looking at call_user_func for possible solutions (thank you) I found this:
				$args = func_get_args();
				$reflectionObj = new \ReflectionClass($class);
				self::$_instances[$class] = $reflectionObj->newInstanceArgs($args);

Open in new window

Which works. I wonder which is faster?
0
 
LVL 34

Expert Comment

by:Slick812
ID: 34900767
you ask "I wonder which is faster?" - - If it works, I would not think that performance (process speed) would be much of a consideration, since it is unlikely it would be used in a large loop executed many times. I always try and use faster code methods, but in php, a scripted language, it is not worth the trouble sometimes to squeak out a slightly faster bit of code.

But I have no idea about the speed, and I would guess,  the only way to really find out is to set up a timed test.

Also thanks for showing me the ReflectionClass, I had not come across that, and it looks very useful for stretching a class, it must be new, many of the methods have no documentation listed.
0
 
LVL 18

Expert Comment

by:Mark Gilbert
ID: 34903034
I would really recommend you have a look at the func_get_args reference page:

http://php.net/manual/en/function.func-get-args.php

There are numerous comments relating to how to get args sanitized, as well as referenced args...which would be a much safer bet than using eval. Eval is so dangerous if your input gets tainted. You don't want any tainting so make sure it's safe before processing, otherwise catastrophic things could happen on your box that you wouldn't even want to consider. These are the types of exploits that script kiddies oogle over.

I also highly recommend the tiny book by O'Reilly called Essential PHP Security isbn #059600656x
0
 
LVL 1

Author Comment

by:Bryan_Heath
ID: 34907920
@Slick812 - Both eval and reflective have the same run time and but appear to use roughly the same resources.  Though obviously reflective seems like a much better choice.

@ingwa - I agree and don't want to use eval.  Which is the entire point of my post.  See my first reply.
0
 
LVL 18

Expert Comment

by:Mark Gilbert
ID: 34908998
Hi Bryan, great to see you are on board with getting rid of eval. If you take a look at the link I provided, you will find the best real world examples for the function, as well as all other functions. I believe the comment I made reference to about referenced args would be the lines you would want to take.

On another note, I wouldn't be too concerned with any hits on performance if you are able to ensure security all the way. It would be better to take a performance hit rather than loose your entire server, or have hackers hijack it for illegitimate means. Server hardware has become cheaper recently and adding space, ram and processor power is much more affordable than it used to be. Rackspace also has some really great cloud based servers that you may find useful if you find you need more power.

Hope this helps.
0
 
LVL 1

Author Comment

by:Bryan_Heath
ID: 34909172
Though I understand your concern you seem to misunderstand how this class will be used.  This makes a class instance thus insuring singleton methodology.  As such I have no idea what the args might be as they will be passed in when a new class is created.  Thus making sanitizing them nearly impossible.  Also the args passed in are merely being pushed off to the parent class.  So if there is a problem its on the side where the class is being created and should be secured there, not here.

As to referencing the args that doesn't make sense in PHP 5.  See the very first note on your link.
0
 
LVL 1

Author Closing Comment

by:Bryan_Heath
ID: 35002982
I found the solution with help from his response
0

Featured Post

On Demand Webinar: Networking for the Cloud Era

Ready to improve network connectivity? Watch this webinar to learn how SD-WANs and a one-click instant connect tool can boost provisions, deployment, and management of your cloud connection.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Author Note: Since this E-E article was originally written, years ago, formal testing has come into common use in the world of PHP.  PHPUnit (http://en.wikipedia.org/wiki/PHPUnit) and similar technologies have enjoyed wide adoption, making it possib…
I imagine that there are some, like me, who require a way of getting currency exchange rates for implementation in web project from time to time, so I thought I would share a solution that I have developed for this purpose. It turns out that Yaho…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

726 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question