Are namespaces really all that useful in frameworks? - php

As far as I can tell, the only reason we have namespacing in PHP is to fix the problem of classes (+ functions & constants) clashing with others classes of the same name.
The problem is that most frameworks setup their autoload and filesystem hierarchy to reflect the names of the classes. And no-one actually require()s or include()s files anymore.
So how does namespacing help this any? Either the class is loaded based off of it's name:
new Zend_Db_Table_Rowset_Abstract;
or off it's namespace
new Zend\Db\Table\Rowset\Abstract;
Either way I am stuck with only being able to create one class with this name.
/var/www/public/Zend/Db/Table/Rowset/Abstract.php
UPDATE
I'm not sure I'm getting the point across.
Even if I created two files with the same class Zend\Db\Table\Rowset\Abstract in them I still couldn't use them together since they both claim the same namespace. I would have to change their namespace names which is what we already do!
This leaves me to belive that the only use for namespaces is function names. Now we can finally have three functions all named the same thing!
Or wait, I forgot you can't do that either since each requires the namespace prefix!
a\myfunction();
b\myfunction();
c\myfunction();
Taking ircmaxell's example:
$model = new \Application\Model\User;
$controller = new \Application\Controller\User;
How is that any different than without?
$model = new Application_Model_User;
$controller = new Application_Controller_User;
This is also a neat sounding feature - but what does it truly do for us?
use \Application\Model\User as UserModel;
use \Application\Controller\User as UserController;
$foo = new UserModel;
$bar = new UserController;
Now you cannot have a class named 'UserModel' since you have a namespace setting for that term. You also still cannot have two classes named under the same alias.
I guess the good thing is that you can rename the long Zend_Db_Table_Rowset_Abstract
use Zend_Db_Table_Rowset_Abstract as RowAbstract;
leading to developer confusion about where the non-existent class "RowAbstract" is defined and coming from in the system.

My impression is that namespaces are used in a cargo cult programming fashion. Because it's new, it gets used like crazy. Deeply nested namespaces, like in Doctrine2, add no further protection against name conflicts. And it's very obvious that \nested\name\spaces are just used to achieve a 1:1 mapping to directory/file names. Clearly a code smell.
But I suppose this phenomenon is also caused by trying to mimick Java module names in PHP. And furthermore the backslash syntax doesn't convey a sensible semantic as in other languages.
Anyway, the ability to rename classes while importing namespaces is a big bon. That's useful when it actually comes to mixing conflicting definitions. And the namespace syntax can simply be added, once an actual name conflict arises. (I see no need to implement namespaces right away, when name conflicts are that rare and for most projects a purely fictional problem.)
If you do it only when required, the awkward namespace syntax never even has to rear its ugly head. If there is only one namespace level to import, you can just use namespace1\Class as LocalName and don't convolute the application with any namespace1\Class syntax. (Still it's a better idea not to use overly generic class names in namespaces.)

Actually, you can create more than one class with the same name
Suppose you have 2 classes:
\Application\Controller\User
and
\Application\Model\User
You couldn't import both into the same file without aliasing one, but you still can define both the same way:
$model = new \Application\Model\User;
$controller = new \Application\Controller\User;
Plus you can import and alias:
use \Application\Model\User as UserModel;
use \Application\Controller\User as UserController;
$foo = new UserModel;
$bar = new UserController;
So it really is quite powerful, as it does let you name your classes however you want (and reference them by arbitrary names inside your code). The only rules are reserved keywords... See: http://www.php.net/manual/en/language.namespaces.importing.php

The point you seem to be missing is that namespace names are composable. I.e. you can do:
use Zend\Db\Table as Table;
$a = new Table\Rowset();
$b = new Table\Fields();
etc. I.e. it allows you to define your context (or set of contexts) and then refer to it. Of course, you can reduce it to just one name, but you don't have to. That btw also helps with generic class names - Fields may be too generic, but Table\Fields less to.
Another thing is if you get sick of Zend tables and want to write your own Db table classes, you change the above to:
use My\Own\Table as Table;
and all the code now uses your set of classes.
Also, you don't actually define the class by the long name. What you do is:
namespace Zend\Db\Table;
class Rowset exteds AbstractRowset {
function doStuff() {
$this->fields = new Fields();
if($this->fields->areBroken()) {
throw Exception("Alas, fields are broken!");
}
}
}
Note that here we have used 4 classes from Zend\Db\Table space, but never once had to refer to them by a long name. Of course, in real life it probably won't be as easy :), but the idea is that code - especially library code - tends to be localized - i.e. if you are in Db part of the library, chances are you are using DB-related classes much more than LDAP or PDF classes. Namespacing allows you to exploit this locality by using shorter names.
You are right that namespacing doesn't help with loading - since class should be still loaded using the full name. But once you've got your loader working, you can use nice aliases instead of ugly full names - just as in the filesystem you can use nice relative paths and symlinks instead of ugly full path.

In your example Zend framework, you can throw namespace Zend; at the top of each class file, remove the Zend_ prefix from all of your classes and functions, and you (mostly) don't need to worry about name collisions ever again. Your Zend_Date class can be renamed as just Date without interfering with the built-in date classes. Meanwhile, users of your framework can write Zend\Date instead of Zend_Date which isn't any longer to type, but they now have several other options for accessing the class more easily.

It's probably not worth it to use namespaces unless you have a big project with multiple developers. I would even argue namespaces are overrated.
For example, in Java (since few people use namespaces yet in PHP I couldn't find any similar examples). These are the choices that come up for List in my IDE (Eclipse):
java.util.List
com.ibm.toad.utils.Strings.List
com.ibm.ws.objectManager.List
com.ibm.ws.webcontainer.util.List
java.awt.List
In this case, I don't really see why they couldn't have just kept java.util.List as the only List, and for example renamed java.awt.List to ScrollingList, which actually describes what it is, makes it more obvious that it is a GUI element, and avoids the collision. I would rather type out a longer and more descriptive class name than have to deal with that.
As for one of the above posters, if everyone in your team is making a class called Database perhaps you need to do some design discussion and use only one Database class instead of shoving each person's personal duplicate into a namespace.

Are you really trying to create a new class called Zend_Db_Table_Rowset_Abstract?
The more likely scenario is that you have a local class called something common like Date, Project, User, or something similar or you have a framework that already has those classes. By having namespaces, there shouldn't be any collisions.
In web2project, we've just added namespace support in v2.0 (but we don't require PHP 5.3) because our classes - like Date, DBQuery, Mail, and a few others - collided with things pretty easily. While we don't have an intention to add an external framework to the system, someone else could pretty easily if they wanted.
Are there less verbose ways of solving the problem? Potentially.. but this worked in the Java world with their piles of libraries, so it's not all new space.

Perhaps if you broaden your view a little :)
"As far as I can tell, the only reason we have namespacing in PHP is to fix the problem of classes (+ functions & constants) clashing with others classes of the same name." - yes this is a huge issue which has caused problems for many years in every language that doesn't have namespaces - everybody makes a class Database, Date, URL etc and this fixes it :)
"The problem is that most frameworks setup their autoload and filesystem hierarchy to reflect the names of the classes. And no-one actually require()s or include()s files anymore." - well actually they do, often, just because some common frameworks have had to come up with practises to work around a lack of namespaces, doesn't mean those work arounds or hacks should null and void the 'real' fix to the issue for all :)
follow?

Related

Silverstripe 4 - accessing core methods

In Silverstripe 3, eveything was autoloaded on demand. That meant that one could know the class and method that they wanted to use. Example:
Debug::dump('dump message');
If I'm understanding the concepts of SS4 correctly, one needs to import the class to the file that you would like to use the method (or property). In the above example, one would need to do something as follows at the top of the file
use /name/space/to/Debug
Debug::dump('dump message');
Is that understanding correct? If so, my real question is how does a developer effectively know the precise location of everything in core? Are they expected to know exactly where in system these core files reside on top of their names and the methods you wish to use? Are there tools or methods to assist in this?
First, just a clarification -- what you're talking about is not autoloading, it's more like aliasing -- but the two are related.
Because the Debug class is no longer in the global namespace, its name is much more verbose (SilverStripe\Dev\Debug). This is known as a fully qualified class name, or "FQCN" for short. There's nothing short, however, about that new name. It's tedious to type, and if the class ever changes its name, you have a lot of updates to make.
To that end, you can use the use statement to "import" that class into the local scope of your file under an alias. By default, that alias is just the trailing part of the FQCN (Debug), but you're also allowed to use any custom alias you like. (use SilverStripe\Dev\Debug as MyDebugger).
SS4 now uses PSR-4 autoloading, for which namespacing is a critical piece. In very short terms, it dictates that the directory structure must match up with the FQCN, e.g. /framework/src/Dev/Debug.php. This makes the autoloading deterministic and predictable.
As for tooling, using a fully powered IDE like PHPStorm is invaluable for doing dev work in a framework with namespaced classes (which is far more the rule than the exception these days). A good IDE, like PHPStorm, will not only autocomplete as you inject a classname, but will also add the use statement for you, among many, many other wonderful time-saving features.
For a more manual approach, api.silverstripe.org is a good place to look up class mappings.

Namespace the real meaning

I have read about namespaces and I played a bit with them just now. But I want to make sure that I got this right.
1) So namespaces are here to save as from duplications of name, really good when you add sources from outside into an application for example
2) Is it a good practice to use namespaces, to avoid duplication
3) Is it a good practice to use a namespace like a folder structure, For example if I have Folder/Folder1/Fileone.php to call my namespace like this: namespace Zend/Folder1/Fileone;
I just wanted to make sure that I got this right, and namespaces are basically here to keep as organized and is good to use them know.
Exactly, namespaces make sure there's no conflict between two libraries/code bases/projects which declare the same classes. It's even useful within one application to separate different classes which may logically be given the same name; say View\User and Model\User.
You can get the same benefit by naming your classes class View_User etc., but this means you always have to use the class by that name. Look at some larger projects like Zend Framework 1.0 to see what a verbose mess this leads to. With namespaces you can use shorter names within the same namespace and alias classes to short names easily.
Yes, it's best to namespace all your code with ProjectName\... or even VendorName\ProjectName\... to make sure you're avoiding collisions with 3rd party code.
Yes, if you correlate folder names to class names (including namespaces), it's easy to use an autoloader. It also simply makes sense.

Using spl_autoload without use keyword on every page?

We have recently been rewriting our PHP application's model code using OO. We have the classes done, and we included namespacing (in the form of Project\Level1\Level2 or whatever). Since this is an already-built application, there are a lot of classes. We are using an autoloader, for ease of loading the classes, which is great. But here's where the hassle comes in.
We have probably 300 pages strewn all across the application, and all of them require a PHP file at the very beginning (a sort of bootstrap script). The autoloader script is required in that bootstrap file.
Now, most of our pages will be using at least one but likely many of the classes. We know that we have two options here:
//either call the classes using qualified names
$person = new Project\Person;
//or include the "use" keyword on every page, so we can alias the classes for ease of use
use Project\Person as Person;
$person = new Person;
But the hassle is that we would really rather not have to do this on every single page in our application:
require_once('../php/bootstrap.php');
use Project\Person\ as Person,
Project\Address\ as Address,
Project\Group\ as Group
Project\CustomField\ as CustomField;
$person = new Person;
$address = new Address;
We tried, for the heck of it, including the use keyword for all our classes in the bootstrap file, but according to the PHP manual, "Importing rules are per file basis, meaning included files will NOT inherit the parent file's importing rules."
It just seems like including these sprawling use statements on every page of our application is creating more hassle than it's worth. And what if we are using 15 classes on one page? Then the use statement would be huge.
My question is this: is it too much hassle? Are we correct in using namespaces, or is it not all that helpful in PHP? And now knowing what we are trying to do, are we doing it right? Is there something we are missing? Should we be calling classes with fully qualified names all the time or something?
(this is my first question on stackoverflow, so please let me know if I need to do anything differently or better with my questions in the future)
While using vanilla Zend Framework Autoloader might not be they way you want to go, the Zend Loader does support custom autoloaders, that can respect namespaces specified in-line or dynamically at run-time. In your case, you are using use Project\Person\ as Person which can become cumbersome, as you already noticed.
Using namespaces with the autoloader will allow you to take advantage of auto loading using simple path traversal to organize classes, without having to append large paths just to get to the interesting parts.
So, instead of new Corp_Assets_Generic_Person_Address, you could keep the folder structure and use new Namespace_Person_Address.
Namespaces avoid clashes in class names. Specially in large applications implementing autoloaders that need to load the right class from a number of different libraries. Using shorter class names makes the code easier to read but may make it harder to maintain. Adding the use statements makes it easier to read and later maintain but then it would be cumbersome to write and refactor. Documenting the expected behavior of the autoloader and using custom autoloaders to make more readable class names would be my suggestion.
In php.ini add your file as a prepend_file

PHP Namespaces: If I'm not going to need to redeclare already taken functions do I need them?

I'm wondering, that if my functions don't have similar names, do I need to use namespaces?
plus I can't get the grips of importing all namespaces from a specific folder...
I'm wondering, that if my functions don't have similar names, do I need to use namespaces?
No.
However, namespacing does offer more benefits than avoiding namespace collisions, it also forces you to maintain good directory and file structures which makes your files easy to find, and an intuitive approach to determining parent/child relationships.
For example:
// Zend/Translate/Adapter.php
class Zend_Translate/Adapter {}
// Zend/Translate/Adapter/Csv.php
class Zend_Translate_Adapter_Csv extends Zend_Translate_Adapter {}
As you can see, classes relating to similar objects are logically grouped together, and as the above code snippet demonstrates, signifies possible parent/child relationships. One caveat, even though a directory may contain a class file along with a sub-directory, it is not guaranteed that the files within the sub-directory will extend the file.
I think you are approaching this question from the wrong perspective. Sure, you can avoid using namespaces if you know you have unique function names. But that is a very short sighted approach and doesn't take into account how complex the application is, how it is structured, etc.
As mentioned by Mike, if you are going to be using frameworks like Zend or Symfony or any other code heavy on Object Orientated Programming, then I would strongly recommend using namespaces. Let's say you want to include a class from a great PHP package. Without namespaces, you will have no assurance there will not be any conflicts.
Additionally, new frameworks like Symfony 2.0 REQUIRE you to use namespaces. So you better get used to it.

What's the benefit of namespaces in PHP?

What's the benefit of namespaces in PHP? I've worked on multiple MVC systems and haven't found much use for them. I'm reading about them here.... is it a problem of sorts that I've never used them? Is it the kind of thing that is a good coding standard to always use?
The main advantage of namespaces doesn't usually come from your own application's code, but from third party libraries. Library maintainers can select appropriate namespaces for their own code and ensure that there are no naming conflicts with your own.
Like any other languages, namespaces allow ambigious names / classes with same name to co-exists while being in two different namespaces.
For example Table class can be referring to a table in a persistent database and a HTML table. I can put namespaces to specifically use the exact table that I want, i.e. \Model\Table and \View\Table respectively.
Namespace is part of good OOP practices. They are really usefull in big web Application because they help to avoid ambiguity between classes. This is a way to organize your application and makes it more readable.
It helps you to avoid name collisions. For example, if you have two packages, and each has a class named Client (or something general like that), then it would lead to a name collision. Before PHP 5.3 the solution to avoid these collisions was to use class names like this: VendorName_PackageName_Classname
As you can see it's not too nice. But now with PHP 5.3 you can use namespaces to come up with cleaner class names.
Imagine you have a huge code base, with thousands of functions, classes and lots of third-party code. And now, two functions happen to have the same name.
That's where namespaces come in - by wrapping your code into namespaces, you can eliminate the possibility of name clashes.
Also, namespaces aid you at structuring your code - everything that belongs to a certain feature or sub-system goes into one namespace.
It also help your code more flexible and clear.
In comparing, Zend_Database_Adapter_Mysql vs Zend/Database/Adapter/Mysql is equal to avoid ambigious names.
// use namespace
use Zend/Database/Adapter/Mysql as DbAdapter;
$dbAdapter = new DbAdapter;
// use naming convention
$dbAdapter = new Zend/Database/Adapter/Mysql;
When use namespace, if adapter is changed, your code would be not modified too many. All actions are only modify 'use' command.
Note that in upon example, the factory method pattern should not be cared.

Categories