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.
Related
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.
So I am using spl_autoload_register to load my classes. However I have this structure for my classes:
classes
classfolder
classfile
So normally when I was including them I was doing this:
include('classes/modules/module_class.php');
Now using spl_autoload_register how would I handle sub folders? I dont have the ability to upgrade to php 5.3 to use namespaces, do I need to do something like this?
$module = new modules_Module();
Then the function I register with spl_autoload_register explodes the _ and uses the first part as the class folder and the second part as the class method. But then I would have to change the class name to modules_Module right? If so is that ok? Or is there a better way of doing this?
Not saying you should do that, but a common pattern in PHP-land is to use case in the filenames as well and not add stuff like _class or class.Module.php:
include('classes/Modules/Module.php');
In PHP 5.2 (no namespace support), you then work with the _ underscores:
class Modules_Module
{
}
So this is how it is normally done. Not saying that you must do it that way. You can also just resolve as you wish. But one should also know about this more common pattern as it helps reading/navigating third party sourcecode.
Basically that's it.
In addition to namespaces (which you can't use) and naming conventions on class names (which would need you to rename all your classes) the only other sane option is to build a classmap: an array that maps class names to the full path of the file that defines them.
Going this way means that you have to update the classmap each time classes are added or modified, a task which is a prime candidate for automation. Look into using Composer's autoload functionality, it can do this on demand and generate the autoload code for you automatically. Composer is so good that it's useful even when you disregard 90% of its features.
As long as your files are arranged in some way that let's you go from the class name to the file name, you can implement your autoloader function however you like. Your autoload function needn't just turn the class name into a directory path: it's job is simply to take a class name, and include the right file, if at all possible.
Keeping your mapping relatively simple is useful for humans, too, though - so you know which file to edit.
For instance, you could say that all classes beginning Mod_ live in a directory called classes/modules but all others live in a directory called classes/general.
You can also use file_exists to check multiple possibilities for one class, but bear in mind that this has some cost, both to PHP checking the filesystem, and to the human trying to remember where the file went.
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? 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.
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?