What happens when a namespace and class share a name in PHP? - php

When using the pseudo namespacing pattern of PEAR and Zend, it is common to come across class heirarchies that look like this:
Zend/
Db.php
Db/
Expr.php
Where DB.php contains a class named Zend_Db and Expr.php contains a class named Zend_Db_Expr. However, when you try to convert the old 5.2 psuedo namespacing into PHP 5.3 namespacing you are presented with a case where a namespace and a class share a name. Since the use operator can import either a namespace or a classname this leads to ambiguity.
Here's an example of an app I'm working on converting:
App/
Core.php
Core/
Autoloader.php
Here the base directory and namespace are App. In the top level of the name space is a Core class:
namespace App;
class Core { }
In the Core directory are various other core classes, some of which use the main Core. Under the pseudo namespacing pattern, this isn't a problem. But in the real namespacing pattern it creates this situation:
namespace App\Core;
use App\Core as Core; // What is this importing? Namespace or class?
class Autoloader {
public function __construct(Core $core) {}
}
Is this defined? What is actually imported here?

Simply both. It is not real import, just a hint for compiler, that every encounter of this alias in class related operations should be expanded to this declaration. In php namespace is just part of class so just think of it like this
$alias = 'Zend_Db';
$zendDB = new $alias;
$aliasExpr = $alias . '_Expr';
$expr = new $aliasExpr;

Related

PHP Extending Class one Folder Back

I have a base abstract class, say Base.php located at /lib/Helper/Base.php. Now, I have another class, say Awesome.php located at /lib/Helper/Awesome/Awesome.php, and this class needs to extend Base.
I have defined my namespaces as follows:
Base.php
<?php namespace Helper;
abstract class Base
{
}
Awesome.php
<?php namespace Helper\Awesome;
class Awesome extends Base
{
}
Right now, this says that class Base was not found. I tried to use require_once and/or include to the path of Base.php and they also didn't work. What am I doing wrong?
You are including the file, and that is the right thing to do. But you are also using
namespaces.
the namespace is not a folder, that means the namespace 'Helper' is not a folder but a logical hierarchy. In order to use the class Base in he logical namespace Helper the Awesome class needs to extend the Base class with the full logical path i.e. \Helper\Base.
namespace Helper\Awesome;
class Awesome extends \Helper\Base {
}
or use the use/as keyword instead (like c# using statement) .
namespace Helper\Awesome;
use \Helper\Base as Base;
class Awesome extends Base
{
}
more information can be fount at the php.net site.
here is a direct reference: http://php.net/manual/en/language.namespaces.importing.php

PHP prepend class names with sub-space for autoloading

I'm just wrapping my head around PHP namespaces and autoloading with composer. I have a question about the following code:
namespace APP\Controllers;
use APP;
use APP\Interfaces;
use APP\Lib;
class PageController
extends Lib\ActionController
implements Interfaces\ControllerInterface
{
//stuff
}
Why do I have to prepend the extends class with the sub-space with 'Lib\' when I already use the line 'use APP\Lib;'? Same goes for the interface. When I don't prepend I get an autoload error. I'm using composer to autoload and have this in my composer.json:
"autoload": {
"psr-4": {
"APP": "app/"
}
}
In app/ I have subfolders Lib, Interfaces and Controllers like so:
/app
/Controllers
/Interfaces
/Lib
I noticed that in other devs code they don't have to do this. I'm confused as to what I am doing wrong.
Thanks for the help.
You are including three namespaces:
use APP;
use APP\Interfaces;
use APP\Lib;
Now if you say just:
extends ActionController
PHP would not know if it is:
APP\ActionController or
APP\Interfaces\ActionController or
APP\Lib\ActionController
If you still wanted to extend it without Lib subspace you would need to do:
use APP\Lib\ActionController; first
use is only there to alias namespaces or class names to shorter names. It's there to avoid having to repeatedly address all classes by their fully qualified name all the time:
$a = new \Foo\Bar\Baz\Quurx();
$b = new \Foo\Bar\Baz\Quurx();
// shorter:
use Foo\Bar\Baz\Quurx;
$a = new Quurx();
$b = new Quurx();
use Foo\Bar is shorthand for use Foo\Bar as Bar. So, you're creating an alias Bar which really resolves to the full name \Foo\Bar. Since APP\Interfaces doesn't resolve to any particular interface in your case, just using implements Interfaces wouldn't mean anything. And if you just used implements ControllerInterface, it would be ambiguous which namespace that resolves to. \APP\Controllers\ControllerInterface? \APP\ControllerInterface? \APP\Lib\ControllerInterface? It's just not clear and cannot be resolved automatically.
So, what you're doing is you're shortening APP\Interfaces to just Interfaces, and then refer to APP\Interfaces\ControllerInterface by just using the shorter Interfaces\ControllerInterface. You could be doing this to make it even shorter:
use APP\Interfaces\ControllerInterface;
.. implements ControllerInterface ..

php psr autoload ambiguity

I am working on a php sdk rewrite project and the client wants to get PSR standards done. I am looking at the standards page here
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
One thing what i am not able to understand, if i use name spaces in my class do i still need to use include or require or use. I mean the whole reason of autoload beats the purpose right ?
For example, say i have a class this way,
namespace Employee\Department;
Class Department
{
//code
}
and i have another class which uses this class by extending it,
namespace Employee\community;
Class Community extends Department
{
//code
}
so does the above code make it to psr-0 standard considering that i have an autoload function exactly thats on the link above.
The second example is going to assume Department is in the Community namespace so in this case you would need a use statement. Also both of your examples would use the namespace Employee not Employee\Whatever for example lets assume the following layout:
Employee/
Community.php
Community/
Manager.php
Department.php
Department/
Manager.php
Then we would see the class/namespaces like the following
namespace Employee;
class Department {
}
///////////
namespace Employee;
class Community extends Department {
}
/////////////
namespace Employee\Department;
class Manager {
}
/////////////
namespace Employee\Community;
use Employee\Department\Manager as BaseManager;
Class Manager extends BaseManager {
}
For your understanding, autoloading works by registering the autoload function in the autoload stack via spl_autoload_register; this allows the function to be invoked whenever a new Class() statement is executed (more info).
On the other hand, the FIG standard for autoloading, PSR-0, defines how a namespace will be translated into a filename by a PSR-0 autoloader function. For example, given the namespace Vendor\Foo, the autoloader will look for the file Vendor/Foo.php having the following code
namespace Vendor;
class Foo
{
public function do()
{
echo "Foo";
}
}
Therefore, following the mandatory requirements, a PSR-0 compliant namespace resolves to the correct PHP file which could otherwise have been included using a require or include.
If I read your intentions correctly, you just need the following namespace in both code snippets:
namespace Employee;
Of course, this is not a PSR-0 namespace because there is no vendor name (unless your vendor name is 'Employee'). Anyway, using this namespace in your two code snippets will work fine.
However, if you intended to keep them in separate namespaces, then the autoloader won't figure out Department in extends Department in the second snippet. You will have to either import the namespace or explicitly specify it as so:
namespace Employee\community;
class Community extends Employee\Department\Department
{
//code
}
I imagine that you did not expect the full class names from your snippets to be Employee\Department\Department, and that is why I first suggested keeping the same namespace for your purposes.

Adding PHP namespaces into an existing ZF1 application

I'm trying to integrate PHP namespaces into an existing Zend Framework project (v1.12). When I add namespacing at the top of a working controller, it doesn't work anymore and the application throws an Invalid controller class error. Here's my controller definition :
namespace MyProject\Controller;
use MyProject\Controller\MyRestController;
class MyFooController extends MyRestController
{
}
and the init method within the Bootstrap.php:
protected function _initAutoload()
{
$autoloader = Zend_Loader_Autoloader::getInstance();
$autoloader->registerNamespace('MyProject');
return $autoloader;
}
Just a guess (have not used ZF for quite some time): Zend will not accept any class as a controller, just those extended from the framework's base controller class. As you don't extend from the frameworks base controller class you see the error.
If that is the reason, take care you initially extended from the base framework controller class or you implemented the needed interface.
namespace MyProject\Controller;
class MyRestController extendes Zend_Framework_Base_Controller_Class_Name_Here
{
...
p.s. the use MyProject\Controller\MyRestController; looks superfluous as that class is in that namespace already. Let's review your code:
namespace MyProject\Controller;
This sets the namespace of the file. That means, non-FQCN will resolve into it. For example:
new MyRestController();
Resolves to the following FQCN:
new MyProject\Controller\MyRestController
Which - oha! - is exactly what you wrote in use:
use MyProject\Controller\MyRestController;
Which means, that this use clause is superfluous, the extend in:
class MyFooController extends MyRestController
Would go to it anyway at first. Because it's the same namespace.
I am facing similar problem now. For me this looks like that Zend cannot properly resolve namespaced controller name. So when I put for example IndexController into namespace \Basic\Controller, it will be not loaded because Zend want to load \IndexController class, which does not exist.
I am thinking about extending standard zend router class, which has method getControllerName.
Then I can set this in bootstrap by:
$router = new \My\Namespaced\Router();
$front = Zend_Controller_Front::getInstance();
$front->setRouter($router);
I didn't tried that code yet but this should work.

Naming namespace with same classname

i have a Namespace Like \Project\User\ with a Class User and \Project\Menu\ with a Class Called Menu.
So if i make an instance i call new \Project\Menu\Menu() but the naming seems bad.
Mabye i call the class name Base (\Project\Menu\Base())?
Or has anyone an idea for a good naming schema .
Iam Coding in PHP.
namespaces should, mainly, resolve conflicts, for example if you are using lot of libraries.
so it is better to have less namespaces in your case
namespace MyProject
{
class User{}
}
namespace MyProject
{
class Menu{}
}

Categories