Can't get constant from dynamic class using namespaces - php

I'm not able to get a constant from a class which is defined by using a string variable and PHP 5.3. namespaces. Example:
use \Some\Foo\Bar;
$class = 'Bar';
echo $class::LOCATION;
where LOCATION is a properly defined constant. The error I get says class Bar is undefined.
If I instead do
$class = "\Some\Foo\Bar";
everything works fine.
Is there anyway to make the first example work?

Using $class::CONST to get a class constant, it is required that $class contains a fully qualified classname independent to the current namespace.
The use statement does not help here, even if you were in the namespace \Some\Foo, the following would not work:
namespace \Some\Foo;
$class = 'Bar';
echo $class::LOCATION;
As you have already written in your question, you have found a "solution" by providing that fully qualified classname:
use \Some\Foo\Bar;
$class = "\Some\Foo\Bar";
echo $class::LOCATION;
However, you dislike this. I don't know your specific problem with it, but generally it looks fine. If you want to resolve the full qualified classname of Bar within your current namespace, you can just instantiate an object of it and access the constant:
use \Some\Foo\Bar;
$class = new Bar;
echo $class::LOCATION;
At this stage you do not even need to care in which namespace you are.
If you however for some reason need to have a class named Bar in the global namespace, you can use class_alias to get it to work. Use it in replace of the use \Some\Foo\Bar to get your desired behaviour:
class_alias('\Some\Foo\Bar', 'Bar');
$class = 'Bar';
echo $class::LOCATION;
But anyway, I might not get your question, because the solution you already have looks fine to me. Maybe you can write what your specific problem is.

Related

Can you avoid specifying a namespace when invoking a class which uses one?

I have an older framework which doesn't implement namespaces. If i try to slowly introduce namespaces, by first declaring one at top of a class declaration, then any invokation of that class will now fail, because it isn't invoked through its namespace. Even though the class file is already included, and there isn't (or so i thought) a need for PHP to know the namespace.
It seems PHP doesn't care that it can find a class by the name Foo, because if Foo is under a namespace, then it will always mandate that you have to specify the namespace as well.
As a simple test, i put this in one file:
<?php
namespace Test;
class Foo {
function bar(): void {
print "Hello world.";
}
}
And this in another:
<?php
include "Foo.php";
$foo = new Foo;
$foo->bar();
It gives me the following error:
Fatal error: Uncaught Error: Class 'Foo' not found
So my question is, can this behaviour be avoided (with some configuration options maybe) to ease the slow transition from a framework that doesn't use namespaces into one that does, or would I have to replace all invokations of all the classes at once before it becomes usable? Are there any hacky alternatives?
you lost namespace :)
$foo = new \Test\Foo();
You need to provide the "path" of your class like this :
<?php
use Test\Foo;
include "foo.class.php";
$foo = new Foo;
$foo->bar();
I don't see another solution...
For more information about Use : https://www.php.net/manual/en/language.namespaces.importing.php

use all classes in a namespace

I've got a namespace named Foo. There are various classes inside that namespace, let say Bar and Baz.
In some other file, I would like to use the Foo namespace and by that gain access to all of it's classes without prefixing them with the \Foo\ClassName.
What I've tried to do was at the top of the script:
use Foo;
And then simply do something like:
$bar = new Bar;
However, when I try that, I get an error: The use statement with non-compound name 'Foo' has no effect, eventually leading to that I have to specify every class I want to use beforehand. Is there any workaround?
PHP's use keyword doesn't work like C++'s using namespace; in the sense that you can't include an entire namespace. You can alias it or include each class.
If you want to do new Bar;, you'll have to do something like this:
use Foo\Bar;
You'd have to do this for each class you need in the Foo namespace. As far as i know there is no workaround.

PHP 5.5 Classname Resolution

PHP 5.5 has implemented as a new feature a new way to retrieve the classname through the syntax ::class:
<?php
namespace Testing;
class Test{}
echo Test::class; // Testing\Test;
This works perfectly, alright? BUt what me and some other friends wanted to know is why this syntax also returns a classname when used alongside an undeclared class. E.g.:
<?php
echo UndeclaredClass::class; // UndeclaredClass
In several other cases an error is raised, but not here. Anyone know, with concrete basis if possible, why does this happen?
Does it have anything to Late Static Bindings or it's just a (temporary) limitation/bug of this brand new feature?
Finally an official answer... relatively speaking. It was presented to me by someone identified by requinix#php.net in a bu report i created today. The only exception is about how involved with PHP development this person is.
TL;DR
PHP doesn't need ot know the definition of a class to get its fully-qualified name. All the required informations are available in compile-time so it doesn't need to load it.
Director's Cut
Namespaces like the uses are resolved in compile-time, i.e., when the file is compiled before its execution. That's why there are strict requirements in order to use them.
Because of all of those requirements, when PHP encounters a class name it can immediately know its fully-qualified name. Thinking of it as a filesystem the namespace would be a directory for relative locations and the use would be symlinks.
The class name is either absolute ("\Testing\Test") or relative ("Test"), and if relative it could be a normal name. [more context required]
namespace Testing {
echo Test::class; // \Testing + Test = \Testing\Test
}
Or an alias:
use Testing\Test as AliasedTest;
echo AliasedTest::class; // AliasedTest + use = \Testing\Test
Without all of this autoloading wouldn't work!
::class is just a new tool to expose information PHP has always known.
This "extended answer" is pretty much the same of what I received as bug report. The reason of so much apparent copy & paste is because, originally, I built up this answer for another Stack Overflow Community
You can use get_class function get the class name with the namespace. It will be the good to use it.
Here is the code which you can try this code:
<?php
namespace Testing;
class Test{
public function abc()
{
echo "This is the ABC.";
}
}
namespace Testing1;
class Test{
public function abc()
{
echo "This is the ABC.";
}
}
// echo Test::class; // Testing\Test;
$test = new Test();
print_r(get_class($test));
// echo "<br>";
// echo UndeclaredClass::class;
?>

Dynamic namespaced class with alias

SO,
I have an issue with dynamic object creation using namespaces.
Here's namespace code:
namespace Foo
{
class Bar
{
}
}
Now, I'm trying to create object of class Bar with:
include('namespace.php');
$sName = 'Bar';
$sClass = '\\Foo\\'.$sName;
$rObj = new $sClass; //correct object
and everything going well with that. But, now I want to use alias and doing something like:
include('namespace.php');
use Foo as Baz;
$sName = 'Bar';
$sClass0= '\\Foo\\'.$sName;
$sClass1= '\\Baz\\'.$sName;
$rObj = new $sClass0; //correct object
$rObj = new $sClass1; //Fatal error
And I'm unable to instantiate an object such way (and accessing via full name still works well).
So, my question is - is it possible to access the class via alias somehow, and, if yes, how? I've also tried to access when using $sClass1='Baz\\'.$sName - no success. Also, I've checked declared classes via get_declared_classes() function, it shows that I have only \Foo\Bar class (no reference to an alias).
I'm not sure if it matters, but I'm using PHP 5.5 version.
Only the parser uses your namespace aliases to canonicalize the class references inside each of your files.
In other words, it doesn't introduce some kind of global alias that other code can use. Once your script has been parsed, the alias is no longer used.
This behaviour is also described in the manual:
Importing is performed at compile-time, and so does not affect dynamic class, function or constant names.

use "global-namespace";

I just wonder if there's a way to make a class behave as if it is in global namespace using a "use" keyword, so this class would behave as namespaced class only from outside of the class.
Something like:
namespace wherever\somewhere\deep\deep\inside;
use \; // root namespace.. note: this doesn't work
class stuff{
//....
}
anyone?
Using the global namespace won't work the way you expect.
By default, you can reference a globally namespaced class by adding a backslash -- eg $x = new \PDO(...);. Trying to use \ won't change that.
If you want to drop the backslash from globally namespaced classes, you need to use each of them specifically. In namespaced PHP, any class reference that doesn't have a namespace is assumed to be in the current namespace, unless it is explicitly referenced by a use statement.
eg:
use \PDO, \SplFileObject;
now we can call new PDO(...) or new SplFileObject() without the backslash. But other global classes that aren't in the use would still need the backslash.
You can access the global namespace if you use brackets like this:
namespace My\Space {
function myScopedFunction() { .. }
}
namespace {
function myGlobalFunction() { .. }
}
I don't think you can. If anyone finds a good way please do share.
I tried the below which didn't work obviously (the writeup is here http://www.siteconsortium.com/h/D0000H.php). I would find it really useful to be able to go to the root namespace this way as a lot of legacy code doesn't use namespaces.
$root = \_\_NAMESPACE\_\_; // error
namespace AA;
function foo() { print " What AA "; }
use ($root); // error
namespace $root; // error can't use var
namespace ""; // error
use "/"; // error
namespace "/"; // error
There are a couple different issues here. One thing I thought was strange is that I can use the keyword require_once $script_name but I can't use the keyword namespace $namespace_name.

Categories