What is the difference between accessing the class through "use" keyword or declaring it as "new" plus the filepath of the class?
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
//if accessed using use keyword
use App\Entity\User;
class SampleController extends Controller
{
public function add(Request $request)
{
//if declared by "use" keyword above
$user = new User();
//if not declared by "use" keyword
$user = new \App\Entity\User();
}
}
If I'm going to use the functions of User class, the results are the same but what's the difference in their declarations?
There is no difference. By using use doesn't include anything. It just imports the specified namespace (or class) to the current scope
new \App\Entity\User(); is same as new User();
You can find more details How does the keyword "use" work in PHP and can I import classes with it?
The use keyword produces an alias for a class or a namespace.
The as keyword introduces the alias. Without as, the alias is the last component of the namespace or class path:
use App\Entity\User as OneUser;
OneUser is the same thing as \App\Entity\User and can be used instead of it everywhere in the current file.
use App\Entity\User;
Here the alias is User (the last component of App\Entity\User). It is the same as (but shorter than):
use App\Entity\User as User;
Aliased are used to write less; the code is easier to read this way.
The aliases are processed at compile time and they are visible only in the file where they are created. The mere presence of the use statement does not have any effect; it only creates a shorter name for a class or namespace but this shorter name is valid only during the compilation of the file that contains it.
The aliased class names are not expanded inside strings. During the compile time they are just text. During the runtime, 'User' is not the same as 'App\Entity\User'.
Accordingly, class_exists('User') returns FALSE but class_exists('App\Entity\User') returns TRUE.
For more insights about how PHP resolves the aliases, read the "Using namespaces: Basics" documentation page.
Related
My question is in three parts:
Does putting in a use statement trigger the autoloader immediately, or does it wait until the class is used? (lazy-loading)
If autoloading isn't done in a lazy-load fashion, could that negatively affect performance?
Which pattern is best to follow, and why? PhpStorm shows "Unnecessary fully qualified name..." as a code issue when the use statement isn't employed.
Here's an example class definition for a Laravel controller with a use statement:
namespace App\Http\Controllers;
use Carbon\Carbon;
class FooController extends Controller
{
/**
* This action uses the Carbon class
*/
public function bar1()
{
return view('foo.bar1', ['now' => new Carbon()]);
}
/**
* This action does not use the Carbon class
*/
public function bar2()
{
return view('foo.bar2');
}
}
The same class without the use statement:
namespace App\Http\Controllers;
class FooController extends Controller
{
/**
* This action uses the Carbon class
*/
public function bar1()
{
return view('foo.bar1', ['now' => new \Carbon\Carbon()]);
}
/**
* This action does not use the Carbon class
*/
public function bar2()
{
return view('foo.bar2');
}
}
1) The class is autoloaded when you perform a new Class() statement.
2) see 1)
3) Which pattern is best to follow and why?:
I'd recommend to use use because you might get into a situation where you have really long namespaces and your code will become unreadable.
From the php docs:
This example attempts to load the classes MyClass1 and MyClass2 from
the files MyClass1.php and MyClass2.php respectively.
<?php
spl_autoload_register(function ($class_name) {
include $class_name . '.php';
});
$obj = new MyClass1();
$obj2 = new MyClass2();
?>
Namespaces are only an additional feature to organize classes.
EDIT: As #IMSoP pointed out in the comments, new is not the only time the autoloader is triggered. Accessing a class constant, static method, or static property will also trigger it, as will running class_exists.
The use statement can be thought of like a C pre-processing macro, if you're familiar with those: it rewrites the current file at compile time to let you write a short name for a long class, function, or constant name. It doesn't trigger autoloading, as it doesn't care if a class exists or not.
For instance, if you write use Foo\Bar\Baz as X, then everywhere that X is mentioned as a class name, the PHP compiler rewrites that to mention Foo\Bar\Baz instead. Only when code mentioning the class (e.g. new X, X::FOO, X::doSomething()) is actually run does it see if there really is a class Foo\Bar\Baz, and trigger the autoloader as necessary.
The common form use Foo\Bar\Baz is just shorthand for use Foo\Bar\Baz as Baz, assigning the alias Baz to the class name Foo\Bar\Baz.
As the manual points out the alias is only processed at compile time, so dynamic lookups will not use it. In the example above, class_exists('X') will return false, but you can use class_exists(X::class) to expand out the alias - the compiler will automatically substitute the full class name as a string, so at run-time, the expression will be class_exists('\Foo\Bar\Baz').
Whether use statements make your code better is therefore entirely a matter of style: the intent is that your code will be more readable without the long fully-qualified class names, but it will make no difference to how the code actually runs.
I want to know if there is a way to get the traits namespace inside itself, I know that I can use self::class to get the classname, but inside a trait it gets the namespace of the class that is using the trait, I don't want to type it's name fixed like new ReflectionClass('trait')
Is there any function or const that can do this?
I'm a little bit confused by your question but if you need the fully qualified name from the trait then you may use __TRAIT__ magic constant and if you only need the namespace of the trait then you may use __NAMESPACE__. For example, declare a trait using a namespace:
namespace App\Http\Controllers\Traits;
trait Methods
{
public function getNamespace()
{
// Get fully qualified name of the trait
echo __TRAIT__; // App\Http\Controllers\Traits\Methods
echo PHP_EOL;
// Get namespace of the trait
echo __NAMESPACE__; // App\Http\Controllers\Traits
}
}
Now, declare a class using another namespace and use that trait inside this class:
namespace App\Http\Controllers;
use App\Http\Controllers\Traits\Methods;
class TraitController
{
use Methods;
public function index()
{
// Call the method declared in trait
$this->getNamespace();
}
}
(new TraitController)->index();
The predefined magic constants __TRAIT__ (since 5.4.0) and __NAMESPACE__ (since 5.3.0) is used so use which one is needed. Tested in php v-5.4.0. Check the demo here.
Also, if you want to get the fully qualified name of the trait from the class that is using it then you may use NameOfTheTrait::class (NameOfTheClass::class/NameOfTheInterface::class) but this is available since php v-5.5.
Also be careful when using self::class. The self::class will give the fully qualified name of the class where you've used it because the self always references the lexical scope (where it's physically used) since the scope of self is determined during the compile time so you may get unexpected results if you inherit a class where a self::class statement is used. In other words, if you call any static method from a child class then the calling context will be still the parent class if you use self in your parent class, in that case you need to use static instead of self. This is actually another topic so please read more on php manual about Late Static Binding.
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use app\models\Category;
use app\components\NewsBehavior;
class ModelTestController extends Controller
{
The class app\components\NewsBehavior exists, but Netbeans gives warning:
Unused use statement (on the line: use app\components\NewsBehavior;).
NewsBehavior class can not be use directly since it's behavior.
It means you defined it, but didn't use it (at least explicitly) within the current class.
If your don't need it in current class, just remove this declaration.
Otherwise if you configuring behaviors class like a string (for example: 'class' => 'app\components\NewsBehavior', obviously this declared class is not used directly and in the current form this declaration in use is redundant.
However there is another way of passing class with static className() method:
'class' => NewsBehavior::className(),
If you will use that, that IDE notice will disappear since now you are explicitly referring to that class.
Official docs:
yii\base\Object className()
Are there performance considerations when importing classes with the use statement in PHP and more specifically laravel 4.x ?
for example often times i have many use statements in my controllers as such:
use OrganisationController;
use Input;
use Redirect;
use Validator;
use View;
use Organisation;
use Sentry;
use User;
use Str;
use Lang;
use Application;
use Job;
use Upload;
class ApplicationController extends OrganisationController {
...
In my opinion, it should not effect on performance because, when you use a class that is not in the same namespace you use it with a preceding backslash like
\View::make(...);
This way you just telling that, the View class is within the global namespace, to make the code clean you can use use statement top of your class like
use \View, \Redirect, \Validator; // more
class WhatEver extends BaseController {
function index()
{
//...
return View::make(...);
}
}
So, in either way, php is loading (include/require) the class whenever it founds any use of the class but when it's not in the scope of current namespace you must provide the namespace and it could be directly from the code like
\View::make(...);
Or maybe using a use statement to keep your code clean but in both ways, php is loading the class during run time (if not already loaded) but you have to provide the right location (with namespace).
Have encountered an issue I can't seem to figure out now by myself.
Using Symfony autoload module.
Here's my factory:
namespace Core\Factories;
use \Core\Gateway;
class DatabaseAccessFactory {
// Define client type
const DEF = 'mongo';
public function createObject($type) {
switch($type) {
case self::DEF:
return new MongoClientGateway();
break;
default:
return false;
}
}
}
Example of /Core/Gateway/MongoClientGateway.php
<? namespace Core\Gateway;
class MongoClientGateway implements MongoDbGateway {
public function setUp(){
}
public function query(){
}
public function save(){
}
}
So, basically I'm using "use" keyword to load gateway namespace into my current one, and then I try to instantiate a class that is under \Core\Gateway namespace, but it says class is not found. Am I missing something?
You need to specifcy the class as well
use Core\Gateway\MongoClientGateway
or access the class with the namespace you used
new Gateway\MongoClientGateway
Btw, there's no need for the first "\" in use \Core\Gateway
It's use Foo\Bar, without leading backslash.
use Foo\Bar does not mean that every Class implicitly resolves to Foo\Bar\Class now. use Foo\Bar is shorthand for use Foo\Bar as Bar, so you can reference the namespace Foo\Bar using merely Bar. use is not "importing a namespace", it's aliasing a namespace to a shorter name.
Therefore you need to write Gateway\MongoClientGateway, or use Core\Gateway\MongoClientGateway explicitly if you want to be able to write just MongoClientGateway.
you used "use" wrong.
waht "use" does, is to tell your code where class comes from.
sample code:
use \my\namespace\className
new ClassName();
this will make the className accassible without a namespace.