PHP namespaces and the implements keyword - php

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

Related

Is there any benefit from explicitly defining all used classes and namespaces at the beginning of PHP class?

Consider these two classes:
namespace Foo\Bar;
use LogicException;
use Memcached;
class Baz extends Memcached
{
public function testBaz()
{
throw new LogicException('Not implemented');
}
}
The same class could be written as:
namespace Foo\Bar;
class Baz2 extends \Memcached
{
public function testBaz()
{
throw new \LogicException('Not implemented');
}
}
Is there any diffrence in performance of these two classes? What if we use Composer's optimized autoloading?
Also consider these two classes:
namespace Foo\Bar;
use Acme\Demo;
class Kaz
{
public function init(Demo\UnitA $unitA, Demo\UnitB $unitB)
{
// do something
}
}
The same could be coded as:
namespace Foo\Bar;
use Acme\Demo\UnitA;
use Acme\Demo\UnitB;
class Kaz2
{
public function init(UnitA $unitA, UnitB $unitB)
{
// do something
}
}
And again the same questions: is there any performance diffrence between those two? What if we use Composers optimized autoloading?
To clarify the questions: is there any performance change?
I know what use is for, how to alias class names etc. I just wondered iof there is any performance hit useing one/or the other method.
use operator imports an external fully qualified name or gives it an alias in your namespace. Classes are loaded when you use them, not on import. So it will not make any difference on autoloading.
But using shorter class names in the code is a benefit, use it whenever you want.
Update
Importing is performed at compile-time so there should not be any difference in performance if you are using any kind of opcode cache like APC or OPcache (even if you are not using any it should be really insignificant change to not use the use operator).
Btw if you have concerns about the performance of your code the best thing is to use profilers. There are many of them like xdebug, blackfire. I personally prefer to use xhprof.
The main benefit: you don't have to write as much.
With simple cases like
use \classname;
that is just a backslash, but with more nested namespaces it can be a real timesaver
use \framework\section\library\someotherclass;
also, you can mock classes, change a used class without having to change it through the whole code, or use one class twice with different names:
use \framework\section\library\fakeclass as realclass;
more information: php namespace importing

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.

The use of "use"

I was just playing around with my IDE and I noticed that when I use the "Fix code" option on a class it adds a bunch of lines on the top of the following type
use Someclass;
use \Ano\therClass;
use Iface;
...
I was wondering what exactly is the purpose of this, since the classes are going to be loaded on demand, is there a need to explicitly declare which classes are going to be used?
Using use you can basically have different objects, functions, etc. with the same name, thanks to namespaces. When you write use in your code, you tell PHP to import items of a namespace and give it an alias.
Read more: http://php.net/manual/en/language.namespaces.importing.php
When U create a class, name it's package with keyword namespace
<?php
/**
* CacheException.php
*/
namespace Doctrine\ORM\Cache;
class CacheException extends Exception {}
Elsewhere use can import only one class from package:
use Doctrine\ORM\Cache\CacheException;
throw new CacheException('Failed to cache');
Also use imports overal package with all it's classes:
use Doctrine\ORM\Cache;
throw new CacheException('Failed to cache');
More at http://php.net/manual/en/language.namespaces.importing.php

Php namespace - repeating Use in each class

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 :)

How does the keyword "use" work in PHP and can I import classes with it?

I have a file with a class Resp. The path is:
C:\xampp\htdocs\One\Classes\Resp.php
And I have an index.php file in this directory:
C:\xampp\htdocs\Two\Http\index.php
In this index.php file I want to instantiate a class Resp.
$a = new Resp();
I know I can use require or include keywords to include the file with a class:
require("One\Classes\Resp.php"); // I've set the include_path correctly already ";C:\xampp\htdocs". It works.
$a = new Resp();
But I want to import classes without using require or include. I'm trying to understand how use keyword works. I tried theses steps but nothing works:
use One\Classes\Resp;
use xampp\htdocs\One\Classes\Resp;
use htdocs\One\Classes\Resp;
use One\Classes;
use htdocs\One\Classes; /* nothing works */
$a = new Resp();
It says:
Fatal error: Class 'One\Classes\Resp' not found in C:\xampp\htdocs\Two\Http\index.php
How does the keyword use work? Can I use it to import classes?
No, you can not import a class with the use keyword. You have to use include/require statement. Even if you use a PHP auto loader, still autoloader will have to use either include or require internally.
The Purpose of use keyword:
Consider a case where you have two classes with the same name; you'll find it strange, but when you are working with a big MVC structure, it happens. So if you have two classes with the same name, put them in different namespaces. Now consider when your auto loader is loading both classes (does by require), and you are about to use object of class. In this case, the compiler will get confused which class object to load among two. To help the compiler make a decision, you can use the use statement so that it can make a decision which one is going to be used on.
Nowadays major frameworks do use include or require via composer and psr
1) composer
2) PSR-4 autoloader
Going through them may help you further.
You can also use an alias to address an exact class. Suppose you've got two classes with the same name, say Mailer with two different namespaces:
namespace SMTP;
class Mailer{}
and
namespace Mailgun;
class Mailer{}
And if you want to use both Mailer classes at the same time then you can use an alias.
use SMTP\Mailer as SMTPMailer;
use Mailgun\Mailer as MailgunMailer;
Later in your code if you want to access those class objects then you can do the following:
$smtp_mailer = new SMTPMailer;
$mailgun_mailer = new MailgunMailer;
It will reference the original class.
Some may get confused that then of there are not Similar class names then there is no use of use keyword. Well, you can use __autoload($class) function which will be called automatically when use statement gets executed with the class to be used as an argument and this can help you to load the class at run-time on the fly as and when needed.
Refer this answer to know more about class autoloader.
use doesn't include anything. It just imports the specified namespace (or class) to the current scope
If you want the classes to be autoloaded - read about autoloading
Don’t overthink what a Namespace is.
Namespace is basically just a Class prefix (like directory in Operating System) to ensure the Class path uniqueness.
Also just to make things clear, the use statement is not doing anything only aliasing your Namespaces so you can use shortcuts or include Classes with the same name but different Namespace in the same file.
E.g:
// You can do this at the top of your Class
use Symfony\Component\Debug\Debug;
if ($_SERVER['APP_DEBUG']) {
// So you can utilize the Debug class it in an elegant way
Debug::enable();
// Instead of this ugly one
// \Symfony\Component\Debug\Debug::enable();
}
If you want to know how PHP Namespaces and autoloading (the old way as well as the new way with Composer) works, you can read the blog post I just wrote on this topic: https://enterprise-level-php.com/2017/12/25/the-magic-behind-autoloading-php-files-using-composer.html
You'll have to include/require the class anyway, otherwise PHP won't know about the namespace.
You don't necessary have to do it in the same file though. You can do it in a bootstrap file for example. (or use an autoloader, but that's not the topic actually)
The issue is most likely you will need to use an auto loader that will take the name of the class (break by '\' in this case) and map it to a directory structure.
You can check out this article on the autoloading functionality of PHP. There are many implementations of this type of functionality in frameworks already.
I've actually implemented one before. Here's a link.
I agree with Green, Symfony needs namespace, so why not use them ?
This is how an example controller class starts:
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class WelcomeController extends Controller { ... }
Can I use it to import classes?
You can't do it like that besides the examples above. You can also use the keyword use inside classes to import traits, like this:
trait Stuff {
private $baz = 'baz';
public function bar() {
return $this->baz;
}
}
class Cls {
use Stuff; // import traits like this
}
$foo = new Cls;
echo $foo->bar(); // spits out 'baz'
The use keyword is for aliasing in PHP and it does not import the classes. This really helps
1) When you have classes with same name in different namespaces
2) Avoid using really long class name over and over again.
Using the keyword "use" is for shortening namespace literals. You can use both with aliasing and without it. Without aliasing you must use last part of full namespace.
<?php
use foo\bar\lastPart;
$obj=new lastPart\AnyClass(); //If there's not the line above, a fatal error will be encountered.
?>
Namespace is use to define the path to a specific file containing a class e.g.
namespace album/className;
class className{
//enter class properties and methods here
}
You can then include this specific class into another php file by using the keyword "use" like this:
use album/className;
class album extends classname {
//enter class properties and methods
}
NOTE: Do not use the path to the file containing the class to be implements, extends of use to instantiate an object but only use the namespace.

Categories