Resetting a namespace in PHP? - 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

Related

PHP - Fatal error: Uncaught Error: Class 'Contentful\Delivery\Client' not found [duplicate]

I am trying to call my model file from another folder. I have provided both of these file structure.
I am getting this error:
Uncaught Error: Class 'App\Models\Providers' not found in /Applications/XAMPP/xamppfiles/htdocs/pro/app/Scripts/Providers/1/Scrape.php:17
I am calling the model file from a script folder located :
app/Scripts/Providers/1/Scrape.php
In this class I have the below :
namespace App\Scripts\Providers\1;
use App\Models;
Model file is located :
app/Models/Providers.php
Within this file I have the below:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
I have not shared the full content that I have in both of these files. If you would like to see the full content of these files please let me know.
This is how the Scrape.php looks like
<?php
namespace App\Scripts\Providers\1;
use App\Models\Providers;
class Scrape {
public function __construct() {
$test = new \App\Models\Providers();
die(print_r($test, true));
}
}
$obj = new Scrape();
You can't have a namespace that starts with a number.
Namespaces follow the same basic rules for variable names:
A valid variable name starts with a letter or underscore, followed by any number of letters, numbers, or underscores
(Emphasis mine).
Thus, your declaration
namespace App\Scripts\Providers\1
is basically invalid.
From that point forward, all bets are off.
First, change your namespace to a valid identifier (and I would advise choosing something more reasonable and recognizable than numbers, you can have descriptive names and there is simply no reason not to):
namespace App\Scripts\Providers\GroupWhatever
Logically, you'll have to rename the folder where this file resides. It used to be
app/Scripts/Providers/1/Scrape.php
so rename that directory to
app/Scripts/Providers/GroupWhatever/Scrape.php
(In both cases, replace GroupWhatever with something that makes sense for your application and domain).
From that point forward, if the class \App\Models\Providers exists at app/Models/Providers.php, it should work.
Important:
Another problem that there could exist, is that is not very clear what Scripts/Scrape.php is or how is it called.
This should work if you are executing Scrape.php from within Laravel, by calling a Laravel controller or console application.
If you are calling this script directly (e.g. by executing php app/Scripts/Providers/1/Scrape.php (or the corrected app/Scripts/Providers/GroupWhatever/Scrape.php) this simply won't work, since the autoloading logic is not run at all.
If you are executing your script manually, on top of the above changes you need to include composer autoload script, which is located at vendor/autoload.php.
Basically, add this line close to the top of your Scrape.php:
require_once dirname( __DIR__ ) . '/../../../vendor/autoload.php';
(I think I put the appropriate amount of go-up-one-dir path-segments, but you make sure it matches the correct path in your installation).
Once that is in place, the autoloader will be run, and classes will be found.
In your Scrape.php, change your namespace to:
<?php
namespace App\Scripts\Providers\p1;
From PHP manual comment,
namespace (even nested or sub-namespace) cannot be just a number, it
must start with a letter. For example, lets say you want to use
namespace for versioning of your packages or versioning of your API:
namespace Mynamespace\1; // Illegal
Instead use this: namespace
Mynamespace\v1; // OK

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.

What does this notation mean in PHP?

I noticed following notation in PHP. What does it mean?
$locales = GeneralUtility::makeInstance(Locales::class);
i have problems understanding parameter of makeInstance. Locales seems to be another static class. What means notation of
Locales::class
explicitly? What kind of parameter will it expect?
According to the documentation, http://php.net/manual/en/migration55.new-features.php#migration55.new-features.class-name, you can use it to get the fully qualified name of a class.
In your case, let's assume the Locale class is defined like this:
file1.php
<?php
namespace App\Core;
class Locale {}
echo Locale::class; // output - App\Core\Locale
In a separate file, you could require/autoload the file,
file2.php
<?php
require_once #pathToFile1/file1.php;
use App\Core\Locale;
echo Locale::class; // output - App\Core\Locale
We can also see from this that we no longer have to save our class name in a variable as we can always call Locale::class and get going.
To address one of the comments on the question, yes, class is a keyword and using it for function name usually result in a parse error.. That changed in PHP 7 though...thus you can define a function and name it class, function etc. It's best not to do this though unless you think it's absolutely necessary.

Facebook PHP SDK 4.0: using classes in subsites

I think this is very simple for many of you, but in the moment I got stuck with this. I have the following part of code:
header.php
include "facebook/autoload.php";
use Facebook\FacebookRedirectLoginHelper;
test.php
include "header.php";
$helper = new FacebookRedirectLoginHelper($redirect_url);
Why do I always get this error:
Fatal error: Class 'FacebookRedirectLoginHelper' not found in test.php on line
I thought when I include a PHP file, classes can also be used. But in this case not, why? I think I do not understand how this autoload and use works, so I would be happy for some explanation.
PHP does not inherit the namespaces nor the use statements of included/required files. This is intentional as otherwise if you include 2 files using a class aliased the same way you will get errors and you might not need all those classes in firs place.
If a class requires a namespace it has to have use statement defined with the full namespace to the particular class they need. Except in the cases where there might be aliasing. For example if you have:
// file1.php
use \My\Cool\LogWriter as Writer;
and
// file2.php
use \My\Cool\FileWriter as Writer;
Now both classes are accessible as Writer.
// test.php
require 'file1.php';
require 'file2.php';
In which case if you don't declare which class from which space you want this will give nasty error that class Writer is defined, which is true, but it is also true that the two classes are 2 separate ones.
For more information on namespaces in PHP5 see (http://php.net/manual/en/language.namespaces.php).
As a side note:
Every file, if not namespace declaration is provided is considered in the global namespace.
If a use is without leading slash the namespace might be considered relative to the current. (unsure but I think it depends on the autoloader?) (Reference here: https://stackoverflow.com/a/4879615/1747193)

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.

Categories