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.
Related
I am learning PHP namespaces. There is one small piece i do not understand, example:
use Hello\Hello2;
require 'Hello/Hello2/Hello.php';
$h = new Hello2\Hello();
echo $h->sayHello();
To me, when i say: use Hello\Hello2 it seems to me i am in namespace Hello2 and so i do not understand why i have to instantiate my object like this:
$h = new Hello2\Hello();
Why not just like this (cause i am already in namespace Hello2)
$h = new Hello();
Regards,
Marcel
It is important to understand that with these use statements you declare aliases (implicit, like in your example OR explicit).
So when you're writing
use Hello\Hello2;
you're basically writing
use Hello\Hello2 as Hello2;
As in you declare the alias Hello2 for the namespace Hello\Hello2. Think of it as a search and replace mechanism.
If you want to use directly the class name, you will have to use the fully qualified name of the class:
use Hello\Hello2\Hello;
...
new Hello();
UPDATE:
Why not just like this (cause i am already in namespace Hello2)
No, you're not in the Hello2 namespace. In order to "be" in a namespace, you have to use the namespace statement. You can be in a single namespace at a time, but you can declare multiple use statements, which again are "just" aliases (or shortcut declarations if you wish) for other namespaces, classes, functions or even constants.
More details in the PHP manual: https://www.php.net/manual/en/language.namespaces.importing.php.
I have a lot of classes in multiples subfolders that I load using this autoloader :
spl_autoload_register(function ($class) {
$class = str_replace('\\', DIRECTORY_SEPARATOR, strtolower($class));
if(file_exists(FILES_PATH.'classes/'.$class.'.class.php')){
require_once(FILES_PATH.'classes/'.$class.'.class.php');
}
});
So if i do new Folder\subFolder\Myclass, it works.
The classes in folders are all in a namespace.
All these classes must use the database class, and the problem is here :
When the class is in a namespace and search the database class, it can't find it.
(DB class is in global namespace)
So I try to put "use BDD" (Bdd is the db class) and it still doesn't work, because Bdd is using PDO and so i must do "use bdd, pdo;" in EVERY classes of the project...
I find this stupid. Is this normal ?
Is there a better way to autoload, without using namespaces ?
It's pretty darn simple:
If you're in a namespace like so:
namespace Foo;
all names of all classes are resolved relative to that namespace. Any Bar will mean the class Foo\Bar, not the "global" Bar. If you want to refer in any way, shape or form to a class which is not in the same namespace, say Bar\Baz (class Baz from the namespace Bar), you have two choices:
use a fully qualified name for the class, e.g.:
\Bar\Baz
where the leading \ means the class name shall be resolved from the top namespace, not the current local one, or
if this is getting annoying to do every time, alias it using:
use Bar\Baz;
which is shorthand for
use Bar\Baz as Baz;
which means any time you use "Baz" in this namespace you mean the class Bar\Baz, not Foo\Bar\Baz.
Yes, this applies to each file individually. If you want to refer to PDO in some namespace in some file, you either have to write \PDO to make it resolve to the "global" PDO class or you write use PDO at the top of the file to make a convenience alias. That's how namespaces work.
This applies to all use cases of any class name:
new \PDO
\PDO::staticMethod()
\PDO::CONSTANT
You can explicitly say that BDD is in the global namespace by doing this in your code:
$foo = new \BDD();
Then you should not need to use it.
Moving answer from one of my comments ;)
Using use \Pdo; in BDD class fixed the world :)
I'm trying to rewrite an OO PHP site (that loosely follows an MVC structure) so it uses namespaces - and want to follow PSR-0.
In the current site I have a class (called APP) which is full of static methods that I call all over the place to handle things such as getting config data eg; APP::get_config('key').
Obviously with namespacing, I would need to call \TheNameSpace\App::get_config('key'). I use this class frequently, so want to avoid having to prefix the namespace every time I use it. I do call methods in it from within other classes, which would usually be under a sub-namespace - so changing the namespace at the top of the file won't really work.
So, I guess my question is, what is the easiest way to have a 'global' class with methods that I can call anywhere without having to prefix with the namespace each time?
namespace Foo;
use Bar;
Then you do not have to do \Bar\fn
So in your case:
namspace Foo;
use TheNameSpace\App;
App::get_config('blah')
Read the section in the php manual on using/aliasing namespaces.
http://www.php.net/manual/en/language.namespaces.importing.php
You can exclude the namespace by using "use". You can name it whatever you want.
use TheNamespace\App as App //You can name it anything here
App:config('key');
At top of your scripts add
use TheNameSpace\App as MyApp
for example. You can then use it like
app = new MyApp();
in your scripts. Of course you needn't to use an alias here. Just
use TheNameSpace\App
app = new App();
will work, too.
A global class that's implementing this one is bad style and you shouldn't do it like this:
class MyApp extends TheNameSpace\App { }
....
myApp = new MyApp();
Getting this error when I put use Blog; at the top.
Warning: The use statement with non-compound name 'Blog' has no effect
in...
Blog is my namespace in which I have 3 classes: Article, List and Category and a few functions.
If I change my statememnt to use Blog\Article; then it works...
Can't I just specify the namespaces I want to use? Do I need to provide classes?
What if I have functions within that namespaces? When I call them outside of the namespace, I'm forced to prepend \Blog\ to each one's name...
PHP's use isn't the same as C++'s using namespace; it allows you to define an alias, not to "import" a namespace and thus henceforth omit the namespace qualifier altogether.
So, you could do:
use Blog\Article as BA;
... to shorten it, but you cannot get rid of it entirely.
Consequently, use Blog is useless, but I believe you could write:
use \ReallyLongNSName as RLNN;
Note that you must use a leading \ here to force the parser into knowing that ReallyLongNSName is fully-qualified. This isn't true for Blog\Article, which is obviously already a chain of namespaces:
Note that for namespaced names (fully qualified namespace names containing namespace separator, such as Foo\Bar as opposed to global names that do not, such as FooBar), the leading backslash is unnecessary and not recommended, as import names must be fully qualified, and are not processed relative to the current namespace.
http://php.net/manual/en/language.namespaces.importing.php
Since this question appears as the first result on Google for this error I will state how I fixed it.
Basically if you have a framework, say like Yii2 you will be used to having to do declare classes like:
use Yii;
use yii\db\WhatEver;
class AwesomeNewClass extends WhatEver
{
}
You will get this error on Use Yii since this class has no namespace.
Since this class has no namespace it automatically inherits the global symbol table and so does not need things like this defining, just remove it.
The use statement in PHP is really just a convenience to alias a long namespace into something that may be a little easier to read. It doesn't actually include any files or do anything else, that effects your development, besides providing convenience. Since, Blog isn't aliased as anything you aren't gaining any of the convenience. I could imagine you could do something like
use \Blog as B;
And that may even work. (It could be argued you actually lose convenience here by obscuring but that's not what the question is about) Because you're actually aliasing the Blog namespace to something else. Using Blog\Article works because, according to the docs:
// this is the same as use My\Full\NSname as NSname
use My\Full\NSname;
So your snippet would be equivalent to:
use Blog\Article as Article;
if you don't want to use 'as' syntax like
use \Blog as B;
define a namespace for the file
namespace anyname;
use Blog
The error "The use statement ... has no effect..." also pops up if you try to use a trait before a class definition.
use My_trait; // should not be here
class My_class{
// use My_trait; should be here instead
}
Perhaps it's something like
namespace Path\To\Your\Namespace\Blog;
use Blog; // Redundant
class Post {
public $linkedArticle;
public function __construct($article = null)
{
$this->linkedArticle = $article ?? new Blog\Article();
}
}
Blog is already available, because that's the namespace you're in, so you can use new Blog\Article(); without use Blog; at the top. That's exactly what the error tells you - the added line has no effect.
Pointless:
use SingleNonNestedClassThatIsAlreadyPresentInTheCurrentNamespace;
Useful:
use SingleNonNestedClassThatIsAlreadyPresentInTheCurrentNamespace as Phew;
If you on the other hand wish to use new Article() then you can do it like this.
namespace Path\To\Your\Namespace\Blog;
use Blog\Article; // Equivalent to "use Blog\Article as Article;"
class Post {
public $linkedArticle;
public function __construct($article = null)
{
$this->linkedArticle = $article ?? new Article();
}
}
In practice you'd do something like
// Fairly separated domains
use Some\TooLong\Namespace\App\User;
use Some\TooLong\Namespace\App\Ecommerce;
use Some\TooLong\Namespace\App\Auth;
but not necessarilly
// Two tools in same domain
use Some\TooLong\Namespace\App\Ecommerce\Cart;
use Some\TooLong\Namespace\App\Ecommerce\Checkout;
as well. I'm positive there are better examples than this ;)
use MyNamespace;
class NonPersistentStorage implements StorageInterface
Both are in MyNamespace. Yet PHP looks for MyNamespace\NonPersistentStorage and StorageInterface (instead of MyNamespace\StorageInterface). Am I missing something?
PHP Namespaces work a bit different than in other languages. When you import a namespace, you aren't really bringing classes into scope, you're just aliasing the namespace. Importing only one level of namespace does absolutely nothing. Even when you import something, you still need to reference its bottommost namespace.
For example, if you have this:
foo.php:
namespace Bar\Baz\Biz;
class Foo
{}
Here is how you use it:
blah.php:
use Bar\Baz\Biz;
$var=new Biz\Foo();
See how I still have to reference it using Biz, even though I imported it?
However, you can get around this using aliases:
blah.php:
use Bar\Baz\Biz\Foo as Foo;
$var=new Foo();
As you can see, I no longer have to qualify it.
Unfortunately, however, there is no "import all" in PHP; if you want to do what's done above, you have to alias each and every class you want to import.
Actually, that "use" declaration does absolutely nothing. You should import (use) namespaces when they are deeper in the namespace hierarchy (e.g. use Foo\Bar\Baz) or when you want to give them an alias (e.g. use Foo as Bar). I think you wanted to declare that the file itself belongs to MyNamespace:
namespace MyNamespace;
class NonPersistentStorage implements StorageInterface { /* ... */ }
Or, you may also want to import separate functions and classes, using the same syntax as for namespaces.
Try using:
use MyNamespace;
class NonPersistentStorage implements MyNamespace\StorageInterface