Solved

Better way to dynamically load instance w/ args

Posted on 2011-02-14
11
209 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
  • 6
  • 2
  • 2
  • +1
11 Comments
 
LVL 17

Expert Comment

by:Dushan911
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
 
LVL 33

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
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 33

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:ingwa
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:ingwa
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

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Introduction Many web sites contain image galleries; a common design for these galleries includes a page with a collection of thumbnail images.  You can click on each of the thumbnail images to see the larger version of the image.  This is easily i…
Since pre-biblical times, humans have sought ways to keep secrets, and share the secrets selectively.  This article explores the ways PHP can be used to hide and encrypt information.
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…
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

743 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

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now