I always thought the main goal of a namespace is to prevent name collision and ambiguity.
#1 problem fixed by namespaces from php.net:
Name collisions between code you create, and internal PHP
classes/functions/constants or third-party
classes/functions/constants.
However, most languages implement the "use" keyword in some way to alias or import other namespace to the current one. I know how it works, but I don't understand why such functionality is ever used.
Isn't using a 'use' keyword effectively defeating the purpose of a namespace?
namespace core\utils;
class User {
public static function hello(){
return "Hello from core!";
}
}
//---------------------------------------------------
namespace core2\utils;
class User {
public static function hello(){
return "Hello from core2!";
}
}
//---------------------------------------------------
namespace core2;
//causes name collision, we now have two different classes of type 'utils\User'
use core\utils; //without this line the result is 'Hello from core2'
class Main {
public static function main(){
echo utils\User::hello();
}
}
Main::main();
//outputs Hello from core!
?>
Am i missing something or is usage of 'use' keywords really generally discouraged?
Either way, under what circumstances is it actually a good idea to sacrifice the encapsulation?
I used to use use, but now I am not sure when use should be used.
Edit: Alright let me get this straight: If I use 'use' to get short name, how is that better than just declaring the class in global namespace? See below:
namespace core\utils\longname {
class User {} //declare our class in some namespace
}
//------------------Other File---------------------------
namespace { //in another file import our long name ns and use the class
use core\utils\longname\User as User;
new User();
}
^ What is the advantage of namespacing like that against this declaration:
namespace {
class User {} //declare our class in global namespace
}
//------------------Other File---------------------------
namespace { //in another file just use the class
new User();
}
Is there any difference at all between the two?
+1 Very Interesting question
My Opinion
The keyword use as so many uses and functionality imagine this
use core\utils\sms\gateway\clickatell\http\SmsSender as SmsCSender
use core\utils\sms\gateway\fastSMS\ftp\Smssender as SmsFSender
Now Compare
if(!SmsCSender::send($sms))
{
SmsFSender::send($sms);
}
To
if(!core\utils\sms\gateway\clickatell\http\SmsSender::send($sms))
{
core\utils\sms\gateway\fastSMS\ftp\SmsSender::send($sms);
}
Conclusion
Without namespace and use i would not be able to achieve such a clean readable code so what i think is that namespace and use complement each other rather than 'use' defeating the purpose of a namespace
Related
I am trying to alias a static method from a utility/helper class, the documentation does not give anything regarding static methods and using those defined there doesn't work for static methods (as it seems so).
So say I have this class:
namespace App\Helpers;
class HTTP {
public static function extract_path_from_url( string $url ) {
$parsed_url = wp_parse_url( $url );
if ( ! isset( $parsed_url['path'] ) ) {
return false;
}
return (string) $parsed_url['path'];
}
}
then trying to use it on a different file:
<?php
echo \App\Helpers\HTTP::extract_path_from_url( 'http://example.com/test' );
that one above works
but trying to alias it:
<?php
use \App\Helpers\HTTP\extract_path_from_url as extract_path;
echo extract_path( 'http://example.com/test' );
would output
Fatal error: Uncaught Error: Call to undefined function App\Helpers\HTTP\extract_path_from_url()
even:
<?php
use \App\Helpers\HTTP::extract_path_from_url as extract_path;
echo extract_path( 'http://example.com/test' );
shows this weird error:
Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)
Is this possible?
Regards,
Aliasing doesn't magically convert methods into functions, try this instead
<?php
use \App\Helpers\HTTP as extract_path;
echo extract_path::extract_path_from_url( 'http://example.com/test' );
Also (it should go without saying) when you alias this only affects the namespace and class name, not methods of the class. These are generally used for 1 of 2 things. Resolving naming conflicts
use NamespaceOne\Someclass;
use NamespaceTwo\Someclass as SecondClass;
If these were both put without an alias then using
Someclass::method()
Would be ambiguous.
The second thing they can be used for is if you need a lot of classes imported from one namespace. Such as this:
use App\Exceptions\NoFile;
use App\Exceptions\FileSize;
use App\Exceptions\FileType;
throw new NoFile();
throw new FileSize();
throw new FileType();
Can be done this way:
use App\Exceptions as E;
throw new E\NoFile();
throw new E\FileSize();
throw new E\FileType();
Which is not only shorter, but easier to maintain if you change the namespace you have to only change it for the alias and then all is good. So in short it's not really intended for what you want to use it for.
Wrap it
You can always make a wrapper for it:
if(!function_exists('extract_path_from_url')){
function extract_path_from_url($url){
return \App\Helpers\HTTP::extract_path_from_url($url);
}
}
And then call it to your hearts content. Performance wise you do have an extra call by wrapping it, but generally wrappers make it easier to maintain. For example if you rename that method or class, you can change it in the wrapper and everything is good. So there is an argument to be made for either option.
You don't have to check if the function exists, but depending on how your overall system works it may not be a bad idea, so I included it in the example just for the sake of completeness. Personally in a case like this, I don't see any issue putting it right in the same file with the class, just remember to load it. If you are using autoloading the functions won't be included unless you manually load the file or otherwise force it to autoload. Assuming nothing else uses the class first, of course.
One method I have used in the past that I really like, is to make a file named http_functions (classname + _functions) and then add a static method to the class that registers the functions:
class HTTP {
public static function regester_fuctions(){
require 'http_functions.php'
}
}
Then when you call HTTP::regester_fuctions() it autoloads HTTP class and includes all the functional wrappers. In fact I do this very thing in my really super awesome debug print class (queue shameless plug) https://github.com/ArtisticPhoenix/Debug
Just some thoughts, enjoy!
A workaround is to use a namespaced helpers.php file and define 'simple' functions in it, which simply pass through arguments.
// lib/My/Deeply/Nested/Namespace/MyClass.php
<?php
namespace My\Deeply\Nested\Namespace;
class MyClass
{
public static function aVeryUsefulFunction(string $var): string
{
// ...Do some stuff
return $magic;
}
}
// lib/helpers.php
namespace App;
use My\Deeply\Nested\Namespace\MyClass;
function doMagic(...$args)
{
return MyClass::aVeryUsefulFunction(...$args);
}
// templates/my-view.php
<?php use function App\doMagic; ?>
<div>I am doing <?= doMagic('magic') ?>!</div>
Note that by using the spread operator ...$args in my 'pass through' function I can change the requirements of the 'target' function without having to update it in two places.
This will break IDE completion, as it will only know to suggest ...$args rather than string $var. I don't know of a way to docblock a function to tell it to read parameters from another function.
As manual says you can import via use classes, functions and constants. Method of a class (even a static one) is not a function.
So, for example you have:
namespace My\Super\NameSpace;
const MY_CONST = 42;
class MyClass {
public function do() { /* code */ } // this is NOT a function
public static function doStatic() { /* code */ } // this is NOT a function too
}
function my_function() { /* code */ } // this is function
In some other file you can write:
namespace YaNamespace;
use const My\Super\NameSpace\MY_CONST;
use My\Super\NameSpace\MyClass;
use function My\Super\NameSpace\my_function as func_alias;
And that's all items you can import with use.
If you try using class_exists() inside a method of a class in PHP you have to specify the full name of the class--the current namespace is not respected. For example if my class is:
<?
namespace Foo;
class Bar{
public function doesBooClassExist(){
return class_exists('Boo');
}
}
And Boo is a class (which properly autoloads) and looks like this
namespace Foo;
class Boo{
// stuff in here
}
if I try:
$bar = new Bar();
$success = $bar->doesBooClassExist();
var_dump($success);
you'll get a false... is there an alternative way to do this without having to explicitly specify the full class name ( i.e. class_exits('Foo\Boo') )?
Prior to 5.5, the best way to do this is to always use the fully qualified class name:
public function doesBooClassExist() {
return class_exists('Foo\Boo');
}
It's not difficult, and it makes it absolutely clear what you're referring to. Remember, you should be going for readability. Namespace imports are handy for writing, but make reading confusing (because you need to keep in mind the current namespace and any imports when reading code).
However, in 5.5, there's a new construct coming:
public function doesBooClassExist() {
return class_exists(Boo::class);
}
The class pseudo magic constant can be put onto any identifier and it will return the fully qualified class name that it will resolve to.......
I'll try to describe the situation I'm having problems with:
I have one main folder. I keep all files in there (empty classes for a reason), and one sub-folder, containing the same files, with all implementations here (empty classes extend them).
the main folder's namespace is declared as Project/Folder, and the sub-folder as Project/Folder/Subfolder. These are class's declarations:
namespace Project\Folder;
class Foo extends Subfolder\Foo { }
namespace Project\Folder\Subfolder;
class Foo { }
What I want to achieve is to be able to call other classes from inside of the Project\Folder\Subfolder\Foo through these empty classes on the lower level, with only its name, e.g.:
namespace Project\Folder\Subfolder;
class Foo {
function bar() {
Another_Class::do_something();
}
}
By default, there will be called Another_Class from the Project\Folder\Subfolder namespace. I want this to refer to Another_Class from the Project\Folder namespace with the same syntax - is that possible?
I hope I explained this clear enough, if not, write a commend, and I'll try to make it clearer.
You can achieve that using the use statement.
use Project\Folder\Subfolder\Another_Class as SomeAlias;
// ...
SomeAlias::doSomething();
// or
$object = new SomeAlias();
$object->doSomething();
Alternatively, you would have to reference the entire namespace:
\Project\Folder\Subfolder\Another_Class::doSomething();
// or
$object = new \Project\Folder\Subfolder\Another_Class();
$object->doSomething();
More information here.
I read an article about namespaces in PHP. But I don't get what they are used for?
<?php
namespace MyProject {
// Regular PHP code goes here, anything goes!
function run()
{
echo 'Running from a namespace!';
}
}
I also read the PHP.net manual about it, but didn't quite get it.
I had a tough time as well, just think of it as a way to help the compiler resolve names.
So there is no ambiguity.
You could have two developers writing completely different classes but with same type identifier.
The class names could be the same. Grouping in namespaces helps the compiler/interpreter will remove the ambiguity.
So namespace Developer1.CoolClass is quite different from namespace Developer2.CoolClass
In the PHP world, namespaces are designed to solve two problems that authors of libraries and applications encounter when creating re-usable code elements such as classes or functions:
Name collisions between code you create, and internal PHP classes/functions/constants or third-party classes/functions/constants.
Ability to alias (or shorten) Extra_Long_Names designed to alleviate the first problem, improving readability of source code.
PHP Namespaces provide a way in which to group related classes, interfaces, functions and constants.
Check Here for details
Namespaces are a way to group your related classes in packages.You can assume namespaces as folders where you keep your files,in a way that both can have the files with same name but different (or same) without any ambiguity.
file1.php
<?php
namespace Foo\Bar\subnamespace;
const FOO = 1;
function foo() {}
class foo
{
static function staticmethod() {}
}
?>
file2.php
<?php
namespace Foo\Bar;
include 'file1.php';
const FOO = 2;
function foo() {}
class foo
{
static function staticmethod() {}
}
/* Unqualified name */
foo(); // resolves to function Foo\Bar\foo
foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo FOO; // resolves to constant Foo\Bar\FOO
/* Qualified name */
subnamespace\foo(); // resolves to function Foo\Bar\subnamespace\foo
subnamespace\foo::staticmethod(); // resolves to class Foo\Bar\subnamespace\foo,
// method staticmethod
echo subnamespace\FOO; // resolves to constant Foo\Bar\subnamespace\FOO
/* Fully qualified name */
\Foo\Bar\foo(); // resolves to function Foo\Bar\foo
\Foo\Bar\foo::staticmethod(); // resolves to class Foo\Bar\foo, method staticmethod
echo \Foo\Bar\FOO; // resolves to constant Foo\Bar\FOO
?>
Consider your write your own class, lets called it Foo. Someone else writes also a part of the project and he calls one of his classes also Foo.
Namespaces solve this problem.
Example:
Namespace MyClasses;
Class Foo
{
}
NameSpace HisClasses;
Class Foo
{
}
$myfoo = new MyClasses\Foo();
$hisfoo = new HisClasses\Foo();
Namespaces are used to isolate functions and class declarations in order to make libraries and "helpers" (files containing functions) more portable. By putting a library in a name space, you reduce the chances of your class names colliding with what an author who may want to use your library may want to call their classes For example, you can have multiple classes named "user" if they're in separate namespaces.
Is there any way to temporary use a namespace ?
I'm using a library to create forms and it uses namespaces, the problem is that I usually want to create a form in the middle of a page, which is thus in the global namespace. Then if I want to call any function of this library I have to prefix everything with Namespace\
Isn't there any way in PHP to do something like this :
Blabla global namespace
strlen('test'); // 4
namespace Namespace
{
test();
}
More global PHP
And have it refer to Namespace\test ?
http://www.php.net/manual/en/language.namespaces.importing.php
<?php
namespace foo;
use My\Full\Classname as Another;
// this is the same as use My\Full\NSname as NSname
use My\Full\NSname;
// importing a global class
use ArrayObject;
$obj = new namespace\Another; // instantiates object of class foo\Another
$obj = new Another; // instantiates object of class My\Full\Classname
NSname\subns\func(); // calls function My\Full\NSname\subns\func
$a = new ArrayObject(array(1)); // instantiates object of class ArrayObject
// without the "use ArrayObject" we would instantiate an object of class foo\ArrayObject
?>
This is about the closest you can get - there's no way to change the default namespace temporarily.
I know this is an old question, and while the accepted answer answers the question as it was asked, I feel like what the OP is really asking is "Can I use items in the global namespace from another namespace. The answer here is a clear and simple yes.
Imagine two classes (one in the global namespace, another in its own:
ClassInGlobal.php
<?php
class ClassInGlobal
{
public static function doStuff()
{
echo 'I do some stuff';
}
}
ClassInNamespace.php
<?php
namespace App\Classes;
class ClassInNamespace
{
public function callDoStuff()
{
\ClassInGlobal::doStuff();
}
}
The above executes fine. All that is required is a leading slash to specify the fully qualified global namespace. Additionally, you could add a use ClassInGlobal declaration right after the namespace declaration and omit the leading slash.
This might translate into the original question by abstracting the namespaced functions into a class Then you could modify the OP's code slightly to acheive this:
require './Namespace/Utilities.php';
Blabla global namespace
strlen('test'); // 4
\Namespace\Utilities::test();
More global PHP
Hope that helps someone coming here looking for that.