PHP __NAMESPACE__ in trait - php

As traits are effectively copy/paste code I was expecting:
__NAMESPACE__
to provide the namespace of the class using it.
Unfortunately, for me, it appears to provide the namespace of the trait.
Why is this?

__NAMESPACE__ contains the namespace of where the code in which __NAMESPACE__ appears was written. It has "literal scope", as far as that concept applies here. The same goes for functions you call within other namespaces or objects you instantiate within other namespaces; they all refer to their own original namespace, not the one the code is currently running in.
Namespaces are really just influencing names, identifiers. For all intents and purposes this:
namespace Foo\Bar;
class Baz {}
is just shorthand for:
class Foo\Bar\Baz {}
which for all intents and purposes is equivalent to:
class Foo_Bar_Baz {}
Namespaces aren't resolved at runtime or have any real influence on the runtime, they're merely serving to prefix names while still allowing somewhat short syntax and not having to constantly write very long names.
__NAMESPACE__ refers to the "name prefix" of the current entity, like Foo_Bar above; nothing more, nothing less.

You're calling it from the context of a method inside the trait itself, so it's perfectly logical for it to return the trait's namespace.
If you're actually asking how to get the class's namespace, take a look here.

Related

Can magic constants be imported in PHP

I cannot find any hint about the fact I cannot import any magic constant.
Trying to like ...
<?php declare( strict_types = 1 );
namespace CodeKandis\MyVendor;
use function dirname;
use const __DIR__;
require_once dirname( __DIR__ ) . '/vendor/autoload.php';
... leads to
Parse error: syntax error, unexpected '__DIR__' (T_DIR), expecting identifier (T_STRING) or \\ (T_NS_SEPARATOR) in /public/index.php on line 5
This question is important while PHPStorm tends to auto import magic constants. And if it's not possible this needs to be reported and fixed.
Edit (2019-07-25)
After I opened an issue this will be fixed in PHPStorm 2019.3.
In PHP only OOP stuff (classes, interfaces, exceptions, errors...) must be fully named-qualified. If you do not specify full name or do not import class into another namespace, PHP will not fallback to global namespace to look for it.
You can also use fully-specified functions or constants. Functions can belong to a namespace, and in fact all core functions belong to global namespace i.e. \. PHP will first look for the function in the current namespace and it will fall back to global functions or constants if a namespaced function or constant does not exist. You can perform micro-optimization if you specify the global namespace explicitly, because PHP will look in the global namespace directly.
namespace A {
function phpinfo(){
echo 'I am bogus';
}
phpinfo(); // vs. \phpinfo()
}
Magic constants are not really constants at all. They change value based on the context. They are more like magic variables. The following code is invalid, because these constants do not belong to any namespace, not even the global one.
namespace A {
echo \__LINE__;
}
At compile time PHP will substitute them with the actual values. They can't be imported either for exactly the same reason, they are not defined anywhere, they are simply an instruction for the compiler.
There are also other things which can't be imported or namespaced, see: List of Keywords.
You cannot use any of the following words as constants, class names, function or method names.
namespace A {
\echo 'hi'; // <-- this line is invalid code
\die(1); // neither is this, even if it looks and behaves like a function
}
Some people confusingly put parentheses after echo or print, treating them like functions, but in reality they are not. The ones listed with parentheses behave like functions accepting parameters, but you can't import them either.

When is it possible to create two controllers with the same name in Symfony2?

I start getting below error after defining a second controller class PostController in different bundle of the same project with the same vendor name.
Fatal error: Cannot redeclare class
Amce\Bundle\CrudzBundle\Controller\PostController in
C:\xampp\htdocs\community\src\Amce\CrudzBundle\Controller\PostController.php
on line 350
I understand that this error means that I have the same name for two classes (OOP). But why even if I have a different bundle with different vendor part, I keep having this error? Does it mean that Synfony2 disallows having two controller classes with the same name in all situations?
Your expert explanations are always appreciated.
I assume the namespace of the culprit class is:
namespace Amce\Bundle\CrudzBundle\Controller
However the file path is:
C:\xampp\htdocs\community\src\Amce\CrudzBundle\Controller\PostController.php
If you copy/pasted the original class, you may have forgotten to change the namespace.
The autoloader would check the this directory for a class that doesn't exist (because of said namespace), however before that, it will have discovered the exact same namespace/class previously.
In PHP 5.3, the namespace is incorporated into the class name. It's important to remember there is no distinction between them, because they are combined at compile time.
Despite the fact you can call __NAMESPACE__ to get the current namespace, in reality this is not performing a dynamic introspection of the code, but instead the magic constant was converted to a constant string at compile time.
The same is true with classes, the namespace becomes part of the class name, and that is how the class is indexed in the internal reference table.
So be mindful of namespaces.

php namespaces: what needs to be qualified?

I am new to using namespaces in PHP and they seem very simple. However, when I added a namespace to the top of a large file containing classes, interfaces, and closures, the code stopped working altogether. Apparently some elements are not qualified properly.
For example:
<?php
namespace MyNamespace;
interface MyInterface { ... }
class MyClass implements MyInterface { ... }
...
I read the documentation at php.net, but I couldn't find a simple list of elements that require qualification under a single named space (either globally or otherwise).
So my question is, if you simply declare a namespace at the top of an otherwise namespace-free file, what elements would require qualification in that scenario?
The way you have it now with everything in one file like that, every class, interface or function in that file is now in the MyNamespace namespace. So from within those classes, interfaces and functions, if you want to refer to a class that is in a different namespace (global or named) you must use it's fully qualified name (or use use statements to declare aliases at top of the file). Note: pre-pending a \ will get you to the global namespace.
Additionally, from outside of the file, if you want to access one of those classes, interfaces or functions you must use the fully qualified name.
MyNamespace\MyInterface
MyNamespace\MyClass
I should also mention, this is not a typical set up. According to psr standards, you should have only 1 class per file. Take a look at http://www.php-fig.org/ for more guidance on standards and practices.

Instantiate a PHP stdClass in my namespace – fatal error

I want to write a small add on for an existing CMS. To do so, I need to extend a class from that CMS' code.
My code will be written inside its own namespace, while the CMS' code does not use namespacing, which basically means it exists inside the global namespace.
Inside my code, I create a new stdClass:
$var = new stdClass();
With that code is place, it always produces a fatal error:
Fatal error: Class 'MyNamespace\something\StdClass' not found in /some/rather/long/path/to/class.php on line 123
Creating the stdClass like this solves that problem:
$var = new \stdClass();
Since I am still pretty new to namespaces, I am not exactly sure what the problem here is?
My guess is that in the first example, the stdClass would be created in the namespace of my class. This actually means the constructor of a class called stdClass existing in my namespace would be called, but since that class does not exist, an error is thrown.
In the second example, I signalize that I want to instantiate the class called stdClass from the global namespace, which somehow suddenly makes sense.
If anyone could elaborate what is happening here I would be very happy.
You appear to understand the concept behind namespaces, and you are headed in the right direction on your analysis of what is happening.
When you are working inside of a namespace you are able to refer to names as unqualified, qualified, and fully qualified.
When you make a namespace you are telling PHP to organize (and resolve) the names of your classes, function, methods, etc. away from the same scope where the built-in PHP code lives along with any other code behind its own namespace. It is away to organize your code and avoid naming collisions among libraries and built-in PHP functions.
Here is a brief on how names get resolved:
If you are trying to resolve a name within the same namespace you can use the unqualified name. So for class \Foo\Bar\Baz you can use new Baz(); as long as you are in namespace \Foo\Bar.
If you are trying to resolve a name that is lower in the same parent namespace you can use the qualified name. So for class \Foo\Bar\Baz you would need to use new Bar\Baz(); if you were in namespace \Foo.
If you are trying to resolve a name that is not in your namespace or is in the global namespace (built-in PHP stuff) then you must use the fully qualified name. If you are in namespace \Foo\Bar and you want to make use of something like the mysqli class you would need to call it by its fully qualified name. e.g. new \mysqli() Your question above is a perfect example that illustrates this. Likewise, if you need to access a class in a totally different namespace you would also need the fully qualified name: new \Third\Party\AppClass();
So to summarize, you are right, the built-in stdClass does not exist in your namespace, therefore you need to access it by the fully qualified name. The reason you must do thing this way had to do with conforming to the rules PHP uses when resolving names.
If you ever need to find out what namespace you are in it will be in the __NAMESPACE__ constant.
In case you haven't already read it, here is the documentation on name resolution in PHP: http://php.net/manual/en/language.namespaces.rules.php
The code is evaluated in your namespace and stdClass doesn't exist there. You are effectively answering your own question with your guess.
Your guess is correct. Look at the comments in "class references" section of Example #1 on this page.
http://php.net/manual/en/language.namespaces.rules.php

Should "use" statement generally reference a [fully qualified] class or a namespace?

There are lots of articles that describe how to use namespaces in PHP-5.3+ I am particularly interested in the conventions in the use statement.
What most articles dot not point out, is that use can reference a namespace or a class. So to reference my class in PSR-0 location Foobar/Helper/Helper.php I can either do this:
use \Foobar\Helper; // This is a namespace
class Whatever {
...
Helper\Helper::MyHelperMethod();
or this:
use \Foobar\Helper\Helper; // This is a class
class Whatever {
...
Helper::MyHelperMethod();
No packages I have seen document which they are using on each use statement, and that can often lead to guesswork.
So, is it bad practice to use one approach or the other? Or perhaps to mix the concepts? Or is it perhaps just one of those things people rarely document?
Or maybe I am just misunderstanding the whole issue?
If you have a namespace \Foobar\Helper, then
use \Foobar\Helper;
allows you to access all classes from the \Foobar\Helper namespace with Helper as a namespace qualifier. The line
use \Foobar\Helper\Helper;
gives you more control over what classes you want to access without the namespace qualifier. On the other hand, it is quite tedious to keep the use declarations in sync with the code during development. On the third hand, it servers as a documentation about what dependencies exist in the file.
To distinguish whether a use statement refers to a namespace or a class, an IDE such as Eclipse PDT helps.
The point of use is to reduce repeatedly typing the same fully qualified class name. It allows you to produce shorter, more readable code. It depends on your situation which is the most readable way to write your code. If you just need one class from a namespace, you can alias it directly. If you need a lot of classes from one namespace, it may make the most sense to alias only up to the namespace. If several classes from separate namespaces are similarly named, it can make code clearer if you only alias up to the namespace. It's entirely up to you and the situation.

Categories