PHP prepend class names with sub-space for autoloading - php

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 ..

Related

Override object creation with same class in another namespace

I'm trying to trick PHP into taking a class from another namespace when trying to create a specific class.
I have two class called "page", the first is in the Core namespace:
namespace Core;
class Page {...}
The second inherits from Core\Page, but adds a few things. It is in the Addons namespace.
namespace Addons;
class Page extends \Core\Page{...}
The reason I want to do this is because I want to build my system with an easy addon engine. Whenever I want, I can add a line in an XML file that tells the autoloading function to take the class in the addon namespace instead of the core namespace.
However, when I try to do this :
spl_autoload_register('loadClass');
public function loadClass(string $className)
{
if (Addon_exist_and_is_registered($className))
{
require "/Addons/$className.php";
}
else
{
require "/Core/$className.php";
}
}
$page = new \Core\Page(); <-- error here
I get an error saying that the class \Core\Page cannot be found in the file Addons\Page.php. This is normal behaviour since the class is not in the same namespace and as such, the fully qualified name cannot find the right class.
Is it possible to trick PHP into thinking that a child class in another namespace is actually the right class? I tried this for the addons class;
namespace Core;
class Page extends \Core\Page{...}
But it breaks the inheritance as you cannot inherit yourself.
Ignore that the classes have the "same name". Because they don't. One class is called Core\Page, the other is called Addons\Page. Those are their names, their fully qualified names to be exact. It's as much a difference as Foo and Bar. If you tell PHP to instantiate Core\Page, then it's going to do that; you can't "trick" it into instantiating Addons\Page, since that's an entirely different class name.
Don't try to "trick" anyone, make your system actually extensible and explicitly allow overriding of class names:
$class = 'Core\Page';
if (...) {
$class = 'Addons\Page';
}
$page = new $class;

Silex namespace : class MainController does not exist

I try to use Silex Framework, but i have a problem with namespaces I think.
when I instanciate my class MainController i have the following error :
Class "MainController" does not exist
here the namespace declaration in my MainController.php :
namespace App\Controllers;
use Silex\Application;
class MainController implements \Silex\ControllerProviderInterface {
....
in my app.php :
$app->mount("/", new \App\Controllers\MainController());
And i've an autoload in my composer.json :
"autoload": {
"psr-4": {"App\\": "app/"}
}
scruture of my project is like it :
|--app/
|----app.php
|----controllers/
|-------MainController.php
|--web/
|----index.php
Thanks a lot for your help :)
I believe your problem is caused by the way you named your directory controllers. According to the documentation about PSR-4 standard:
5) Alphabetic characters in the fully qualified class name MAY be any combination of lower case and upper case.
6) All class names MUST be referenced in a case-sensitive fashion.
So, rename your directory to Controllers and re-run composer update.
Also, take a look at ServiceControllerProvider about the proper way of setting controller instance as a callback. Passing new instance might not be the best (if not wrong) way of doing things. You should be doing something like:
$app->get('/', 'App\\Controllers\\MainController::index');

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.

Using namespaces in Laravel 4

I'm new to Laravel and using PHP namespaces in general. I didn't run into any problems until I decided to make a model named File. How would I go about namespacing correctly so I can use my File model class?
The files are app/controllers/FilesController.php and app/models/File.php. I am trying to make a new File in FilesController.php.
Namespacing is pretty easy once you get that hang of it.
Take the following example:
app/models/File.php
namespace App\Models;
class File {
public function someMethodThatGetsFiles()
{
}
}
app/controllers/FileController.php
namespace App\Controllers;
use App\Models\File;
class FileController {
public function someMethod()
{
$file = new File();
}
}
Declare the Namespace:
namespace App\Controllers;
Remember, once you've put a class in a Namespace to access any of PHP's built in classes you need to call them from the Root Namespace. e.g: $stdClass = new stdClass(); will become $stdClass = new \stdClass(); (see the \)
"Import" other Namespaces:
use App\Models\File;
This Allows you to then use the File class without the Namespace prefix.
Alternatively you can just call:
$file = new App\Models\File();
But it's best practice to put it at the top in a use statement as you can then see all the file's dependencies without having to scan the code.
Once that's done you need to them run composer dump-autoload to update Composer's autoload function to take into account your newly added Classes.
Remember, if you want to access the FileController via a URL then you'll need to define a route and specify the full namespace like so:
Route::get('file', 'App\\Controllers\\FileController#someMethod');
Which will direct all GET /file requests to the controller's someMethod()
Take a look at the PHP documentation on Namespaces and Nettut's is always a good resource with this article
first, load your class with:
$ composer dump-autoload
then
$file = new File;
// your stuff like:
$file->name = 'thename';
$file->active = true;
$file->save();
Section: Insert, Update, Delete on Laravel 4 Eloquent's doc
To namespace your model, at the top of your model class right after the opening
Then when you call from controllers you will call new Whatever\Model;
You probably have to do a dump-autoload with composer the first time around.
have a look to it.. hopefully will clear your query....
<?php
namespace app\controllers;
use yii\web\Controller;
use app\models\users;
class UserController extends Controller{
public function actionIndex()
{
echo "working on .....";
}
}
Namespaces are defined at the top of PHP classes right after the opening php script tag like this:
<?php
namespace MyNameSpace;
When you then want to use the namespaced class in some other class, you define it like this:
new MyNameSpace\PhpClass;
or import it at the top of the file (after namespaces if present) like this:
<?php
//namespace
use MyNameSpace\MyPHPClass;
//then later on the code you can instantiate the class normally
$myphpclass = new MyPHPClass();
In Laravel namespaces can be defined anywhere composer can autoload them, I'd recommend defining namespaces within the app directory. So you can define a namespace like Utils for holding Utility classes by creating a Utils directory in the app directory, creating our utility classes and defining the namespace as we did above.
Afterwards you have run the command to ask composer to autoload classes:
$ composer dump-autoload

What happens when a namespace and class share a name in 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;

Categories