PHP, new variable class in namespace - php

I'm experimenting with PHP 5.3's namespacing functionality and I just can't figure out how to instantiate a new class with namespace prefixing.
This currently works fine:
<?php
new $className($args);
?>
But how I can prepend my namespace in front of a variable classname? The following example doesn't work.
<?php
new My\Namespace\$className($args);
?>
This example yields: Parse error: syntax error, unexpected T_VARIABLE

Try this:
$class = "My\Namespace\\$className";
new $class();
There must be two backslashes \\ before the variable $className to escape it

Here's how I did it:
$classPath = sprintf('My\Namespace\%s', $className);
$class = new $classPath;
Note the single quotes instead of double.

Related

Namespace not working when used as variable?

<?php
namespace Vendor\Package;
$test1 = new Foo\Bar(); // works as usual
$test2 = 'Foo\Bar';
$test2 = new $test2(); // does not work
$test3 = 'Vendor\Package\Foo\Bar';
$test3 = new $test3(); // but this works
I was looking to use $test2 but it doesn't work even though it looks like it should as it's pretty much the same as $test3 which worked.
Is this expected or is there some syntax I need to use for test2 to work?
When you use a dynamic class name, it has to be fully qualified. The documentation says:
One must use the fully qualified name (class name with namespace prefix). Note that because there is no difference between a qualified and a fully qualified Name inside a dynamic class name, function name, or constant name, the leading backslash is not necessary.
Foo\Bar is not fully qualified, it's relative to Vendor\Package that you selected with the earlier namespace statement.
You can prefix your strign with __NAMESPACE__
Vendor\Package\Foo\Bar::__construct
Vendor\Package\Foo\Bar::__construct
Vendor\Package\Foo\Bar::__construct
Repl.it : https://repl.it/repls/BuzzingFairSuperuser
namespace Vendor\Package\Foo;
class Bar
{
function __construct()
{
echo __METHOD__,"\n";
}
}
namespace Vendor\Package;
$test1 = new Foo\Bar(); // works
$test2 = __NAMESPACE__.'\Foo\Bar';
$test2 = new $test2(); // works
$test3 = 'Vendor\Package\Foo\Bar';
$test3 = new $test3(); // works
So I'll see if I can explain this simply. In your first instance "$test1 = new Foo\Bar();", the path to the model is mapped during compile/load time. In the case where "$test2 = 'Foo\Bar'; $test2 = new $test2();", you're trying to call this model during runtime... Unfortunately, at runtime, the linking has already been done, and is not revisited. What this means it that "$test2 = '\Vendor\Package\Foo\Bar'" should work, but a shortened version of the name can't work, as the linking step is not revisited during runtime.

initiate an instance from variable name and namespace in one line

$map_class_name = __NAMESPACE__.'\\'.$map_class_name;
$map = new $map_class_name;
Is it possible to do this in one line like this?
$map = new (__NAMESPACE__.'\\'.$map_class_name);
The above gives
syntax error, unexpected '('
The answer is no, you can't use new with string or expression.
But you can use
$map = new $map_class_name;
Since you use class from current namespace(__NAMESPACE__) you don't have to prefix classname, namespace will be implied.
Alternative solutions
You might use Reflection
$map = (new \ReflectionClass(__NAMESPACE__."\\$map_class_name"))->newInstance();
Another way is to not break line, but I guess this misses the point.
$map_class_name = __NAMESPACE__.'\\'.$map_class_name; $map = new $map_class_name;
IIFE is also possible
$map = (function($n){return new $n;})(__NAMESPACE__."\\$map_class_name");

calling a php namespace with a variable

I'm learning to use the namespaces in php, and I am trying to put a variable in the namespace name when calling a constant.
Here is my code.
fruits2.php
<?php
namespace fruits\red;
const redfruit = 'tomato';
fruits1.php
<?php
namespace fruits;
require_once('fruits2.php');
const myconst = 'banana';
echo myconst; // displays banana
echo '<br>';
echo \fruits\red\redfruit; // displays tomato
echo '<br>';
$color = 'red';
echo \fruits\$color\redfruit; // Parse error: syntax error, unexpected '$color' (T_VARIABLE), expecting identifier (T_STRING)
I don't understand how I can call the constant in this last line. I tried with the following but it is considered as a simple string.
echo '\fruits\\'.$color.'\\redfruit';
I'm pretty sure that I should be able to do it, because I could do something very similar when calling a class in another part of this code:
$name = '\fruits\basket\\'.$color.'\\eat';
$c = new $name(); //this works
Anybody knows the answer to that? Thanks!
Use the constant keyword:
$name = constant("fruits\\$color\\redfruit");
You have to escape the slashes.
Also the name has to be fully qualified (relative to the root namespace).

Using Namespaces but not for default classes

Since yesterday I am going to use namespaces in php and I have a little problem there:
namespace NamespaceName;
use StdClass;
$s = new StdClass;
$s->meow = "Hello World";
echo $s->meow;
Is there any way that I must not include the "use StdClass"?
You just have to put a backspace in your declaration, so that you use StdClass from the global namespace:
$s = new \StdClass;
//^ See here

Use keyword and dynamic class names

use my\Project\FooClass;
$obj = new FooClass(); // ok
$name = 'FooClass';
$obj2 = new $name(); // throws an error that the class wasn't found
Well, I believe the title and the example were pretty enough explanation of my question, so just - why does this throws an error, and how should I deal with this?
Sadly, this is not possible due to the way PHP imports/aliases from namespaces. This can be remedied by using literal namespace definitions, though it no doubt sucks.
As follows:
$r = "my\\Project\\FooClass";
$k = new $r();
There is a patch in the works, or at the very least, it was on PHP's bug report a couple of months back. They will hopefully do something about it.
If it bothers you, you can use class_alias() to remedy it, by the way.
try:
$obj2 = new $name;
Remove the parenthesis
Alternatively:
$obj2 = new {$name}();
Can't explain why this doesn't work. But for how to deal with it:
$name = 'FooClass';
$name = "my\\Project\\FooClass\\" . $name; // prepend namespace
$obj2 = new $name();

Categories