Jump to content

Flaw In Php's Namespace, Cannot Import An Entire Namespace,


Hall of Famer

Recommended Posts

Well its been a while since PHP added namespace support, but so far its still crappy. I am not sure if this has been changed in PHP 5.5, but at least in 5.3.18 and 5.4.9 you cannot do this:

 

namespace A{
class Foo{
 public function bar(){
	 echo "foo bar";
 }
}
}

namespace B{
use \A;
$a = new Foo();
$a->bar();
// This results in a fatal error!
}

 

Instead, you either have to use the whole namespace name or just import classes in a package one by one:

 

namespace B{
 $a = new \A\Foo;
 $a->bar();
 // outputs foo bar;

 use \A\Foo;
 $n = new Foo;
 $n->bar();
 // outputs foo bar;
}

 

This results in a serious problem when you wish to import an entire sub-namespace. In a real application its unlikely you only have one Foo class in the namespace A, so you have to write multiple lines of use statement to import all these classes, which can be quite annoying.

 

You may argue that Aliasing is here to serve the purpose, but honestly aliasing is only useful in a really complicated system with namespace as long as 'Application\Model\User\Member\Profile\ProfileField\AboutMe'. In most occasions aliasing is just as much typing as using the entire namespace name, and serves no practical purpose.

 

You know in Java you can import a package of class using something like 'import javax.swing.*', no idea why in PHP its not possible. Or maybe its already available in PHP 5.5? I dunno.

Edited by Hall of Famer
Link to comment
Share on other sites

PHP requires you to be explicit. That's not necessarily a bad thing. For example, if you can import wildcard namespaces:

 

namespace A{
class Foo{
   public function bar(){
       echo "A";
   }
}
}

namespace B{
class Foo{
   public function bar(){
       echo "B";
   }
}
}

namespace C{
use \A;
use \B;
$a = new Foo();
$a->bar();
}

 

What's echoed?

Edited by xylex
Link to comment
Share on other sites

Because this is PHP and not Java :P

 

But its a really useful feature PHP is missing, not like the syntax which is simply a matter of opinion. Assume you have a UserFactory class to decide which type of user object(Member, Admin, Banned and Guest) to instantiate, all of these user classes are in the subpackage Model\User. You will have to write this many lines in PHP:

use \Model\User\Member as Member;
use \Model\User\Admin as Admin;
use \Model\User\Banned as Banned;
use \Model\User\Guest as Guest;

 

In java, all you have to do is to write this line:

import Model.User.*

 

See how life can be made easier? Sure it may not seem to be a problem when you only needs to import one namespace with four classes, but what if in your controller class you have to import like 5 namespaces and 30+ classes? It will be quite a mess I must say.

 

PHP requires you to be explicit. That's not necessarily a bad thing. For example, if you can import wildcard namespaces:

 

Yeah at times it may be helpful, but you have to agree that its so inflexible. There are more occasions you need to import multiple classes from a namespace than dealing with conflicting class names, and PHP aint good at handling this since you can only import one class at a time.

Edited by Hall of Famer
Link to comment
Share on other sites

use \Model\User\Member as Member;
use \Model\User\Admin as Admin;
use \Model\User\Banned as Banned;
use \Model\User\Guest as Guest;

 

LOL

 

1) The as Class part is redundant

2) Why would you create a class for each user role?

3) Assuming all of them implement a UserInterface, how would you check if you are dealing with a banned user?

 

if ($user instanceof Banned) {

 

Which is:

 

1) Not flexible and also hard-couples your code to an implementation

2) If at some point you wish to create a PrivilegedMember you will have to hunt down all type checking code

   and add it.

3) It's error prone, for example if PrivilegedMember extends Member type checking like this:

 

if ($user instanceof Member) {
  // ..
} else if ($user instanceof PrivilegedMember) {

 

Means a privileged member is no longer so privileged.

 

4) It's boring. A new type means lots of code changes as does privilege changes.

Instead use roles, resources, and privileges:

 

if ($this->acl->isAllowed($this->user, 'content', 'edit')) {

 

Banned is not a role, more a state, since anyone can be banned, afterwards you still have to know what role he has/had, and it can have special behavior like being only temporary. Something that is not easily captured in an ACL

 

if ($user->isBanned()) {
  $this->redirect()->to('/you-are-banned');
}

Edited by ignace
Link to comment
Share on other sites

use \Model\User\Member as Member;
use \Model\User\Admin as Admin;
use \Model\User\Banned as Banned;
use \Model\User\Guest as Guest;

 

LOL

 

1) The as Class part is redundant

2) Why would you create a class for each user role?

3) Assuming all of them implement a UserInterface, how would you check if you are dealing with a banned user?

 

if ($user instanceof Banned) {

 

Which is:

 

1) Not flexible and also hard-couples your code to an implementation

2) If at some point you wish to create a PrivilegedMember you will have to hunt down all type checking code

and add it.

3) It's error prone, for example if PrivilegedMember extends Member type checking like this:

 

if ($user instanceof Member) {
 // ..
} else if ($user instanceof PrivilegedMember) {

 

Means a privileged member is no longer so privileged.

 

4) It's boring. A new type means lots of code changes as does privilege changes.

Instead use roles, resources, and privileges:

 

if ($this->acl->isAllowed($this->user, 'content', 'edit')) {

 

Banned is not a role, more a state, since anyone can be banned, afterwards you still have to know what role he has/had, and it can have special behavior like being only temporary. Something that is not easily captured in an ACL

 

if ($user->isBanned()) {
 $this->redirect()->to('/you-are-banned');
}

 

Well I am just using this as a quick example in which you may have a series of classes from a namespace you wish to import quickly into another namespace. And now you spent an hour writing useless criticism just for explaining how that user system aint working, its completely missing the point I was arguing early on.

Link to comment
Share on other sites

PHP requires you to be explicit. That's not necessarily a bad thing. For example, if you can import wildcard namespaces:

 

namespace A{
class Foo{
   public function bar(){
       echo "A";
   }
}
}

namespace B{
class Foo{
   public function bar(){
       echo "B";
   }
}
}

namespace C{
use \A;
use \B;
$a = new Foo();
$a->bar();
}

 

What's echoed?

 

In other languages with namespaces, the above would, at the very least, result in a runtime error if not a compiler error.

 

For once, I agree with Hall of Famer. PHPs namespace implementation is half-baked, and not keeping in line with other languages that implement the feature. Merely dismissing it as "PHP is not Java, get over it" misses the point. The point is that namespaces could be better.

 

In cases like the example above, it's solved either by using an alias or by explicitly refering to the foo in question. But, one of the entire points of using namespaces is to be able to refer to classes only by their class names. Having to still refer to them by their fully qualified names when there's no naming conflict, even if it's just once, is ridiculous. All it does is add unnecessary boilerplate.

Link to comment
Share on other sites

You will have to write this many lines in PHP:

 

 

No, you only have to write one line like this:

use \Model\User;

 

Then when you use those classes, do:

new User\Member
or 
new User\Admin

 

 

 

In java, all you have to do is to write this line:

import Model.User.*

 

There are a lot of people who frown upon using an import * statement and suggest you should be explicit just like PHP forces you to be.  By doing so it makes it easier to see where exactly a particular class comes from.   As you said what if you're importing a bunch of namespaces into your controller, eg

import Blah.*;
import Bleh.*;
import Foo.*;
import Bar.*;

 

then later on you do something like:

meh = new Meh();

 

What namespace is Meh from?  Dunno, gotta go search the docs to try and fine out.  With PHP, or if you import selectively you'd know right from the code where it comes from.

Link to comment
Share on other sites

 

 

No, you only have to write one line like this:

use \Model\User;

 

Then when you use those classes, do:

new User\Member
or
new User\Admin

 

Nope, this is not what a well-designed namespace system should work. The fact that you have to refer to the class as User\Member and User\Admin instead of just Member and Admin simply kills the purpose of importing namespace. In your case, why not just write the full class name in the format of \Model\User\Member and \Model\User\Admin? How much does it simplify by getting rid of the \Model part? Unless you have a real complicated namespace like App\Model\User\Member\Profile\ProfileField\EditableProfileField, I dont see how it helps practically when you still have to write User\ as prefix for your classes.

Edited by Hall of Famer
Link to comment
Share on other sites

  • 4 weeks later...

Whats most annoying about PHP's namespace is that you have to use \ in front of PHP's builtin-class names such as Exception, ArrayObject and even stdclass. Not mentioning how ugly it is to write something like \ArrayObject, this sure makes it much easier to run into bugs in which the evil backslash \ is missing. I know PHP did this for a reason since you may end up defining your own classes that share the same name with PHP's built-in classes, but in most circumstances its not the case. If PHP provides a wildcard import mechanism, at least we can import all classes from PHP's global space so that we dont have to remind ourselves to use backslash \ sign in front of these built-in class names.

Edited by Hall of Famer
Link to comment
Share on other sites

How much have you actually used namespaces Hall of Famer? Most of your arguments refer to issues that I myself have not found to be an actual problem. Sure, there may be some annoyances, but no language can avoid those (annoyances).

Link to comment
Share on other sites

How much have you actually used namespaces Hall of Famer? Most of your arguments refer to issues that I myself have not found to be an actual problem. Sure, there may be some annoyances, but no language can avoid those (annoyances).

 

Well many people found it not a problem for PHP to be a purely procedural language back in the 90s, so its redundant to bring in OOP? The point is that there's not a way a programming language can meet every coder's need, but a real mature programming language offers a great deal of flexibility to various programmers. The fact that you do not see it a problem not not dictates that the others feel the same way as you do. If you still dont understand, mind elaborating why 'goto' is added in PHP 5.3 when its been argued as a misfeature by many experienced coders? You've gotta give people choices, let them make their own decision on how to write their scripts. Yes no language can avoid certain annoyances, but it's not an excuse to sit here and refuse to improve. You cant be perfect, yet you can always get better.

Edited by Hall of Famer
Link to comment
Share on other sites

" mind elaborating why 'goto' is added in PHP 5.3 when its been argued as a misfeature by many experienced coders? You've gotta give people choices, let them make their own decision on how to write their scripts."

 

Good job answering your own question!

Link to comment
Share on other sites

" mind elaborating why 'goto' is added in PHP 5.3 when its been argued as a misfeature by many experienced coders? You've gotta give people choices, let them make their own decision on how to write their scripts."

 

Good job answering your own question!

 

umm whats your point? PHP right now does not give us a choice for wildcard import, thats what I've been arguing about.

 

 

By the way, here's a question. Given the pseudo-code

use Fruit\*;
use Colors\*;

$o = new Orange();

Where is PHP supposed to find the Orange class?

 

Well ask Java's developers how they handle situations like this with their wildcard import.

 

Sure there are programmers who make mistakes like that, but it cant be helped. You see people getting errors of missing semicolons everyday, so PHP should allow users to conclude a line without semicolon? Oh yeah, all variables should be constants since some amateur programmers end up overwriting them in an unexpected fashion?

 

 

At least, PHP needs to provide auto-importing built-in classes such as ArrayObject and Exception.

Edited by Hall of Famer
Link to comment
Share on other sites

Well ask Java's developers how they handle situations like this with their wildcard import.

 

From a SO comment.

The only problem with it is that it clutters your local namespace. For example, let's say that you're writing a Swing app, and so need java.awt.Event, and are also interfacing with the campany's calendaring system, which has com.mycompany.calendar.Event. If you import both using the wildcard method, one of two things happens:
  • You have an outright naming conflict between java.awt.Event andcom.mycompany.calendar.Event, and so you can't even compile
     
  • You actually manage only to import one (only one of your two imports does .*), but it's the wrong one, and you struggle to figure out why your code is claiming the type is wrong
     
  • In actuality, when you start your code, there is no com.mycompany.calendar.Event, but when they later add one, your previously valid code suddenly stops working (thanks to @Stanchfield for pointing that out)

The advantage of explicitly listing all imports is that I can tell at a glance which class you meant to use, which simply makes reading the code that much easier. If you're just doing a quick one-off thing, there's nothing explicitly wrong, but future maintainers will thank you for your clarity otherwise.

 

 

In the event you do have a conflict, you still have to list some of them out:

import java.sql.*;
import java.util.*;
import java.sql.Date;

More:

http://javadude.com/...mandisevil.html

Link to comment
Share on other sites

Yeah, there are ups and downs with wildcard import, I agree. But you have to understand that there are circumstances that you wont run into naming conflict while its more convenient to import an entire namespace. For instance, with PHP's built-in classes you want to use ArrayObject and Exception without having to add that backslash infront of their names. Another example is utility namespace package, in which all classes are used in the script. Like I pointed out before, there are always programmers who make mistakes, if they mistakenly import two namespaces that have naming conflict its their own problem. Just like newbies missing semicolons, there are always people who make this kind of errors, it cant be helped.

Edited by Hall of Famer
Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.