<p>What are the performance, security, or "other" implications of using the following form to declare a new class instance in PHP</p>

<pre><code>&lt;?php
  $class_name = 'SomeClassName';
  $object = new $class_name;
?&gt;
</code></pre>

<p>This is a contrived example, but I've seen this form used in Factories (OOP) to avoid having a big if/switch statement.</p>

<p>Problems that come immediately to mind are    </p>

<ol>
<li><s>You lose the ability to pass arguments into a constructor</s> (LIES. Thanks Jeremy)</li>
<li>Smells like eval(), with all the security concerns it brings to the table (but not necessarily the performance concerns?)</li>
</ol>

<p>What other implications are there, or what search engine terms other than "Rank PHP Hackery" can someone use to research this?</p>

[{'answer_id': 48035, 'author': 'Paige Ruten', 'author_id': 813, 'author_profile': 'https://Stackoverflow.com/users/813', 'pm_score': 3, 'selected': False, 'text': '<p>It looks you can still pass arguments to the constructor, here\'s my test code:</p>\n\n<pre><code>&lt;?php\n\nclass Test {\n    function __construct($x) {\n        echo $x;\n    }\n}\n\n$class = \'Test\';\n$object = new $class(\'test\'); // echoes "test"\n\n?&gt;\n</code></pre>\n\n<p>That is what you meant, right?</p>\n\n<p>So the only other problem you mentioned and that I can think of is the security of it, but it shouldn\'t be too difficult to make it secure, and it\'s obviously a lot more secure than using eval().</p>\n'}, {'answer_id': 48077, 'author': 'Sam McAfee', 'author_id': 577, 'author_profile': 'https://Stackoverflow.com/users/577', 'pm_score': 2, 'selected': False, 'text': '<p>There may indeed be a performance hit for having to resolve the name of the variable before looking up the class definition. But, without declaring classes dynamically you have no real way to do "dyanmic" or "meta" programming. You would not be able to write code generation programs or anything like a domain-specific language construct.</p>\n\n<p>We use this convention all over the place in some of the core classes of our internal framework to make the URL to controller mappings work. I have also seen it in many commercial open source applications (I\'ll try and dig for an example and post it). Anyway, the point of my answer is that it seems well worth what is probably a slight performance decrease if it makes more flexible, dynamic code.</p>\n\n<p>The other trade-off that I should mention, though, is that performance aside, it does make the code slightly less obvious and readable unless you are very careful with your variable names. Most code is written once, and re-read and modified many times, so readability is important.</p>\n'}, {'answer_id': 48736, 'author': 'pilif', 'author_id': 5083, 'author_profile': 'https://Stackoverflow.com/users/5083', 'pm_score': 4, 'selected': True, 'text': "<p>One of the issues with the resolving at run time is that you make it really hard for the opcode caches (like APC). Still, for now, doing something like you describe in your question is a valid way if you need a certain amount of indirection when instanciating stuff.</p>\n\n<p>As long as you don't do something like</p>\n\n<pre><code>$classname = 'SomeClassName';\nfor ($x = 0; $x &lt; 100000; $x++){\n  $object = new $classname;\n}\n</code></pre>\n\n<p>you are probably fine :-)</p>\n\n<p>(my point being: Dynamically looking up a class here and then doesn't hurt. If you do it often, it will).</p>\n\n<p>Also, be sure that $classname can never be set from the outside - you'd want to have some control over what exact class you will be instantiating.</p>\n"}, {'answer_id': 48742, 'author': 'Brian Warshaw', 'author_id': 1344, 'author_profile': 'https://Stackoverflow.com/users/1344', 'pm_score': 0, 'selected': False, 'text': "<p>I use dynamic instantiation in my custom framework. My application controller needs to instantiate a sub-controller based on the request, and it would be simply ridiculous to use a gigantic, ever-changing switch statement to manage the loading of those controllers. As a result, I can add controller after controller to my application without having to modify the app controller to call them. As long as my URIs adhere to the conventions of my framework, the app controller can use them without having to know anything until runtime.</p>\n\n<p>I'm using this framework in a production shopping cart application right now, and the performance is quite favorable, too. That being said, I'm only using the dynamic class selection in one or two spots in the whole app. I wonder in what circumstances you would need to use it frequently, and whether or not those situations are ones that are suffering from a programmer's desire to over-abstract the application (I've been guilty of this before).</p>\n"}, {'answer_id': 49586, 'author': 'Michał Niedźwiedzki', 'author_id': 2169, 'author_profile': 'https://Stackoverflow.com/users/2169', 'pm_score': 2, 'selected': False, 'text': '<p>Alan, there\'s nothing wrong with dynamic class initialisation. This technique is present also in Java language, where one can convert string to class using <code>Class.forClass(\'classname\')</code> method. It is also quite handy to defer algorithm complexity to several classes instead of having list of if-conditions. Dynamic class names are especially well suited in situations where you want your code to remain open for extension without the need for modifications.</p>\n\n<p>I myself often use different classes in conjunction with database tables. In one column I keep class name that will be used to handle the record. This gives me great power of adding new types of records and handle them in unique way without changing a single byte in existing code.</p>\n\n<p>You shouldn\'t be concerned about the performance. It has almost no overhead and objects themselves are super fast in PHP. If you need to spawn thousands of identical objects, use <a href="http://www.dofactory.com/Patterns/PatternFlyweight.aspx" rel="nofollow noreferrer">Flyweight</a> design pattern to reduce memory footprint. Especially, you should not sacrifice your time as a developer just to save milliseconds on server. Also op-code optimisers work seamlessly with this technique. Scripts compiled with Zend Optimizer did not misbehave.</p>\n'}, {'answer_id': 62327, 'author': 'Seldaek', 'author_id': 6512, 'author_profile': 'https://Stackoverflow.com/users/6512', 'pm_score': 3, 'selected': False, 'text': '<p>I would add that you can also instanciate it with a dynamic number of parameters using :</p>\n\n<pre><code>&lt;?php\n\n$class = "Test";\n$args = array(\'a\', \'b\');\n$ref = new ReflectionClass($class);\n$instance = $ref-&gt;newInstanceArgs($args);\n\n?&gt;\n</code></pre>\n\n<p>But of course you add some more overhead by doing this. </p>\n\n<p>About the security issue I don\'t think it matters much, at least it\'s nothing compared to eval(). In the worst case the wrong class gets instanciated, of course this is a potential security breach but much harder to exploit, and it\'s easy to filter using an array of allowed classes, if you really need user input to define the class name.</p>\n'}, {'answer_id': 62360, 'author': 'Leonid Shevtsov', 'author_id': 6678, 'author_profile': 'https://Stackoverflow.com/users/6678', 'pm_score': 0, 'selected': False, 'text': "<p>One problem is that you can't address static members like that, for instance</p>\n\n<pre><code>&lt;?php\n$className = 'ClassName';\n\n$className::someStaticMethod(); //doesn't work\n?&gt;\n</code></pre>\n"}, {'answer_id': 63437, 'author': 'Edoardo Vacchi', 'author_id': 7849, 'author_profile': 'https://Stackoverflow.com/users/7849', 'pm_score': 0, 'selected': False, 'text': "<p>@coldFlame: IIRC you can use <code>call_user_func(array($className, 'someStaticMethod')</code> and <code>call_user_func_array()</code> to pass params</p>\n"}, {'answer_id': 461564, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 0, 'selected': False, 'text': '<pre><code>class Test {\n    function testExt() {\n    print \'hello from testExt :P\';\n    }\n    function test2Ext()\n    {\n    print \'hi from test2Ext :)\';\n    }\n}\n\n\n$class = \'Test\';\n$method_1 = "testExt";\n$method_2 = "test2Ext";\n$object = new $class(); // echoes "test"\n$object-&gt;{$method_2}(); // will print \'hi from test2Ext :)\'\n$object-&gt;{$method_1}(); // will print \'hello from testExt :P\';\n</code></pre>\n\n<p>this trick works in both php4 and php5 :D enjoy..</p>\n'}, {'answer_id': 14203323, 'author': 'FilmJ', 'author_id': 133221, 'author_profile': 'https://Stackoverflow.com/users/133221', 'pm_score': 1, 'selected': False, 'text': '<p>So I\'ve recently encountered this, and wanted to give my thoughts on the "other" implications of using dynamic instantiation.</p>\n\n<p>For one thing <code>func_get_args()</code> throws a bit of a wrench into things.  For example I want to create a method that acts as a constructor for a specific class (e.g. a factory method).  I\'d need to be able to pass along the params passed to my factory method to the constructor of the class I\'m instantiating.</p>\n\n<p>If you do: </p>\n\n<pre><code>public function myFactoryMethod() \n{\n  $class = \'SomeClass\'; // e.g. you\'d get this from a switch statement\n  $obj = new $class( func_get_args() );\n  return $obj;\n}\n</code></pre>\n\n<p>and then call:</p>\n\n<blockquote>\n  <p>$factory->myFactoryMethod(\'foo\',\'bar\');</p>\n</blockquote>\n\n<p>You\'re actually passing an array as the first/only param, which is the same as <code>new SomeClass( array( \'foo\', \'bar\' ) )</code>  This is obviously not what we want.</p>\n\n<p>The solution (as noted by @Seldaek) requires us to convert the array into params of a constructor:</p>\n\n<pre><code>public function myFactoryMethod() \n{\n  $class = \'SomeClass\'; // e.g. you\'d get this from a switch statement\n  $ref = new ReflectionClass( $class );\n  $obj = $ref-&gt;newInstanceArgs( func_get_args() );\n  return $obj;\n}\n</code></pre>\n\n<p>Note: This could not be accomplished using <code>call_user_func_array</code>, because you can\'t use this approach to instantiate new objects.  </p>\n\n<p>HTH!</p>\n'}]
['https://Stackoverflow.com/questions/48009', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/4668/']