<?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.
Related
example
namespace Foo;
use Test\One;
use Test\Two;
use Test\Three;
class Sample
{}
How can I get the aliases (USE) as an array?
example of what I am looking to get
$test = [Test\One, Test\Two, Test\Tree];
Does anybody have any suggestions without scanning the file?
or is there a PHP function that will return the list aliases as an array?
Any help will be very appreciated.
Assuming I have the following class and the file is located and named as following file name and location src/Foo.php
namespace Foo;
use Test\One;
use Test\Two;
use Test\Three;
class Sample
{}
now I can scan this file
with this function, I can scan that class and get the result expected.
<?php
use \SplFileObject;
class Scanner
{
public static function getUseAliases()
{
$className = new SplFileObject("src/Foo.php");
$use = [];
while (!$className->eof())
{
$alias = explode("use ", $className->fgets());
if(!empty($alias[1]))
{
$use[] = trim($alias[1]);
}
}
$className = null; //Unset the file to prevent memory leaks
print_r($use);//will print my expected output [Test\One, Test\Two, Test\Three]
}
}
I think there should be a better way to get the same results and this is why I posted my current solution. Please let me know your thoughts.
You can try to use this class:
https://gist.github.com/Zeronights/7b7d90fcf8d4daf9db0c
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).
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();
I want to create objects dynamically. Right now I'm creating them manually like this
$obj1 = new Prefix_Myobj();
$obj2 = new Prefix_Other();
$obj3 = new Prefix_Another();
How can I set the part after Prefix_ dynamically? I tried this but it didn't work
$name = 'Myobj';
$obj1 = new Prefix_{$name}();
You need to create a string that specifies the entire class name.
$name = 'Myobj';
$classname = 'Prefix_'.$name;
$obj1 = new $classname();
However, it might be better design to build a class registry of sorts rather than generating class names on the fly like this.
Why do you need this? Maybe there is a better solution for your problem; multiton or dependency injection etc...
It is important to say that if your class is in a specific namespace, you need to inform the full path. Example:
namespace my\path\app;
class MyClass {
$name = 'Myobj';
$classname = 'my\path\app\Prefix_' . $name;
$obj1 = new $classname();
}
This doesn't work:
test.php:
include_once('test-include.php');
$main = new mainClass();
//======================================================================
class mainClass {
function __construct() {
$test2 = new Test2();
echo $test2->var;
}
}
//======================================================================
class Test2 extends Test1 { // test2
var $var = 'b';
}
test-include.php:
// this does get printed out, so I know the include statement is working
echo 'DEBUG: this is the test-include.php file<br>';
//======================================================================
class Test1 { // test1
var $var = 'a';
}
It gives the following error
PHP Fatal error: Class 'Test2' not found in /path/to/test.php on line 8
whereas this does work
test2.php:
// this is in the same position as the include statement in test.php
//======================================================================
class Test1 { // test1
var $var = 'a';
}
$main = new mainClass();
//======================================================================
class mainClass {
function __construct() {
$test2 = new Test2();
echo $test2->var;
}
}
//======================================================================
class Test2 extends Test1 { // test2
var $var = 'b';
}
Why does putting the Base class (Test1) in an include file cause the child class that is extending it to not be found? In other words, the first example is failing because it can't find Test2 when we attempt to instantiate it. This kind of makes sense as we haven't gotten to Test2 in the code execution flow yet. However, in the second example (without the include statement) there's no error, even though it's a similar situation (we haven't reached the Test2 class in code execution yet)
Oh, and this is under version 5.1.6.
UPDATE:
OK, Daff is correct - if I move
$main = new mainClass();
to the end in the test.php example, it works. I would still like to know why it doesn't work if the above line isn't at the end - it works just fine in the test2.php example which doesn't have the $main = new mainClass() line at the end.
UPDATE 2:
OK, I've tried using require, require_once and include in place of include_once - none of these work. And I also added a test echo statement to the test-include.php file and it gets printed out (plus I don't get an error about a non-existent include file) so I know the include statement is working.
This should have something to do with the definition order and that EVERY class should be included before you actually work with them. If you put the call of
$main = new mainClass();
At the end of your script it works fine even with the include file because all the classes are defined already. Eventually you should have a look at the PHP autoload function because you will get rid of these problem with one small function.
OK, I think I may have figured this one out. According to this bug report:
http://bugs.php.net/bug.php?id=30453
PHP 4 allowed classes to be defined after they are used but for PHP 5, in the words of the end poster on the bug thread:
PHP5 supports it [declaring classes
after they are used] for backward
compatibility, but we don't plan
support for all combinations.
So I'm guessing this particular case is one of those unsupported combinations.