Can magic constants be imported in PHP - 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.

Related

PHP __NAMESPACE__ in trait

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.

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.

What does only `namespace` mean in this situation?

Seeing this line in PHP from password_compat, I am not sure what it does:
namespace {
//...
}
Is it similar to wrapping some code in an anonymous function in javascript? What's it purpose?
Note: I know how to normally use namespaces, I just don't understand this, since it looks like a namespace but without any name in it and, for me so far, without any purpose.
It declares the code to be in the global namespace. The purpose of this is that later on in the file there are two functions implemented in a private namespace, and PHP requires that if any namespace is used in the file the first keyword in the file must be namespace. So to mix global and namespaced code in the same file, this is how it needs to look.
See https://github.com/ircmaxell/password_compat/commit/88911e6abebb324cca88f546f04d6e71ce778bd3 for the particular commit.
That definition is to ensure that the file containing it loads in the global namespace. Have a look at this answer
namespace // empty namespace means global
{
// Ensure everything you put here belongs the global namespace
}
But, technically speaking, it is exactly the same as not declaring any namespace at all. In both cases everything in it will belong to the global namespace.

PHP : Only use a class if it exists

Is there a way to make sure that the file exists before using the classes name in a file
This is to avoid errors incase it doesn't exist? I have researched this but nobody tells you how to do it. Maybe thats because there isn't a way or its only a way that secret php coders knew so please dont dislike this question because of the amount of information given about it.
I tried
if (class_exists("Authentication"))
{
use go\Authentication;
}
But I get this error
Parse error: syntax error, unexpected 'use' (T_USE) in C:\xampp\htdocs\index.php on line 29
I also tried this method
if (file_exists("/go/authentication.php") { use go\Authentication; }
And it gave me the same error as the previouse method
Besides of your original intention, in the documentation you can read:
The use keyword must be declared in the outermost scope of a file (the global scope) or inside namespace declarations. This is because the importing is done at compile time and not runtime, so it cannot be block scoped. The following example will show an illegal use of the use keyword:
Which means that it should be used in the top of the file or, at least, in the outermost scope. While your case might be the outermost scope, it is bound to a conditional, which makes your rule illegal, similarly to the example provided in the documentation:
<?php
namespace Languages;
class Greenlandic
{
use Languages\Danish;
...
}
?>
About your problem, you could simply do:
if (class_exists("Authentication"))
$Auth = new Authentication();
However, have a look into autoloading, since that seems more likely what you are looking for.
You are using use wrong!!
The 'use' keyword must be declared in the outermost scope of a file
(the global scope) or inside namespace declarations. This is because
the importing is done at compile time and not runtime, so it cannot be
block
scoped.
As far as loading the class on the fly is concerned. You can use autoloading as suggested in the comments
On a side note. If your class is found inside a namespace such as
namespace foo\bar;
class tar{
}
then the right way to check it exists is not
class_exists('tar')
but rather:
class_exists('\foo\bar\tar')
or
use foo\bar;
class_exists('tar');

Resetting a namespace in PHP?

How can I "reset" a namespace to the global one? Given the following code:
namespace foo;
include 'myfile.php';
myfile.php will now try to load all of its classes in the foo namespace, even though its classes are in the global namespace. Now it wouldn't be a big deal to swap the order of those lines, but how would I deal with myfile.php having an autoloader? It will try to load the classes in namespace foo.
Namespaces work on a per-file basis. If myfile.php doesn't declare any namespace then everything in it will belong to the global namespace, regardless of the namespace in which include was used.
Long story short, namespace declarations only apply to their own file, not includes.
myfile.php should declare the namespace that it wants to be in. If you want to ensure that myfile.php loads in the global namespace, I believe you can put
namespace // empty namespace means global
{
}
around the body of myfile.php. Make sure that you use the braces, or else you'll redefine the rest of the file in which myfile.php is included to also be in the global namespace.
Maybe I didn't understand your question well ; in that case, could you provide an example of what you get, and what you'd expect ?
Are you sure it will try to load the functions from myfile.php in the foo namespace ?
Considering I have one file (temp-2.php) that looks like this :
<?php
namespace foo;
function my_function_this_file() {
var_dump(__FUNCTION__);
}
my_function_this_file();
include 'my_other_file.php';
my_function_the_other_file();
And another one (my_other_file.php) that looks like this :
<?php
function my_function_the_other_file() {
var_dump(__FUNCTION__);
}
When I call the first one from my browser, I get this output :
string 'foo\my_function_this_file' (length=25)
string 'my_function_the_other_file' (length=26)
This seems to indicate the second function is not inside any namespace, except the global one -- which corresponds to the fact that it's not declared in any namespace.
If I remember correctly, the "namespace" instruction is only valid for the file it is used in, and not for included files.
The Import names cannot conflict with classes defined in the same file page from the namespaces FAQ seems to indicate that too.
Hope this helps, and I understood the question correctly...
EDIT : btw, swapping the order of the to lines, like this :
<?php
include 'my_other_file.php';
namespace foo;
Wouldn't work : the "namespace" instruction must be the first one of the file : you'll get a Fatal Error, if you do that :
Fatal error: Namespace declaration statement has to be the very first statement in the script
I'd just like to chime in on this with my findings. Since PHP cannot handle exceptions in __toString methods, the solution is to do it yourself: something along the lines of
public function __toString()
{
try {
return $this->draw();
} catch ( \Exception $e ) {
die( \error::_getExceptionPage( $e ) );
}
}
However what becomes really weird, the namespace of the call to error::_getExceptionPage($e) becomes the same as the class in which __toString was defined - and I wasn't able to find a way around that except prefixing everything in my exception handling code with \, i.e. every call to any class in getExceptionPage must become \someClass::staticMethod().
Same goes for included files, everything - all code since the thrown exception becomes embedded in the namespace of the faulty class. Tested with PHP 5.3.17

Categories