Monday, June 30. 2008Migrating OOP Libraries and Frameworks to PHP 5.3With PHP 5.3 coming up on the horizon, I'm of course looking forward to using namespaces. Let's be honest, who wants to write the following line? $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); when the more succinct: $viewRenderer = HelperBroker::getStaticHelper('viewRenderer');
could be used? (Assuming you've executed However, while namespaces will hopefully lead to more readable code, particularly code in libraries and frameworks, PHP developers will finally need to start thinking about sane standards for abstract classes and interfaces. For instance, we've been doing things like the following in Zend Framework:
These conventions make it really easy to find Abstract classes and
Interfaces using namespace Zend::Controller::Request class Http extends Abstract { // ... } Spot the problem? 'Abstract' is a reserved word in PHP. The same goes for interfaces. Consider this particularly aggregious example: namespace Zend::View abstract class Abstract implements Interface { // ... } We've got two reserved words there: Abstract and Interface.
Stas, Dmitry, and I sat down to
discuss this a few weeks ago to come up with a plan for migrating to PHP
5.3. In other OOP languages, such as Python, C#, interfaces are denoted by
prefixing the interface with a capital 'I'; in the example above, we would
then have namespace Zend::Controller::Request class Http extends ARequest { // ... } and: namespace Zend::View abstract class AView implements IView { // ... } Another thing that looks likely to affect OOP libraries and frameworks is autoloading, specifically when using exceptions. For instance, consider this: namespace Foo::Bar class Baz { public function status() { throw new Exception("This isn't what you think it is"); } }
You'd expect the exception to be of class namespace Foo::Bar class Baz { public function status() { throw new namespace::Exception("This is exactly what you think it is"); } }
By using the I'd like to recommend other libraries adopt similar standards -- they're sensible, and fit already within PEAR/Horde/ZF coding standards. What say you? Comments
Display comments as
(Linear | Threaded)
I think prefix 'A' for abstract classes is not 'sane step'. Should by Zend_Controller_Action named Zend::Controller::AAction in PHP 5.3? It is abstract class too.
There is a next problem. Namespace naming style doesn't match the Zend naming style. By renamimg Zend_Controller_Action class to Zend::Controller::Action, we have class Action in namespace Zend::Controller. That's right. This class throws Zend_Controller_Action_Exception. In the respect to namespace model, this should be 'ActionException' in the same namespace, i. e. Zend::Controller::ActionException. But simple replacing _ with :: leads to Zend::Controller::Action::Exception, with means Exception class in the very different namespace. This blog post was by no means exhaustive in the steps Zend Framework will need to take to migrate to namespaces, asd was never intended to be. I wanted to primarily point out some places where obvious changes would need to be made, and a potential solution. We will be making other naming changes for 2.0 as well, so that we can support namespaces fully.
Hi Matthew,
I think it's a very good idea to come up with some best practices on how to use namespaces and have as many PHP projects as possible adopt them. Thanks for starting this. That being said, I'd suggest using AbstractSomething instead of ASomething. But more important: to avoid confusion with namespaces and procedural code (I know you don't have that in ZF, but other people have), I'd suggest prefixing every function name by something hopefully unique. This makes it possible to distinguish between calls to a function in a namespace and a static class call. Take this example: namespace foo::bar; function baz() namespace foo; class bar { public function baz() } Now is foo::bar::baz() a call to the function or a static method call? You can easily change your program's behaviour by adding either one to an existing program, so I suggest to prefix the function name, e.g. fn_baz(). Stefan +1 for AbstractSomething instead of ASomething. This seems a lot more readable to me. I can't give you a good reason why, but ISomething seems sufficient to me but InterfaceSomething seems overly verbose. Just pointing out the contradiction in my opinion
Hi Stefan!
Well, in times of OOP I would rather refactor any global functions into some sensible class than to add prefixes to their names... Put another way: I don't expect many procedural coders to jmp n the namespaces-train. Karsten Is there a real benefit of migrating existing libraries (esp. popular ones like ZF) to use namespaces? I see a lot of potentional for creating bugs and breaking compatibility for existing users, just to save a few kb.
Nevertheless, good to see folks are ironing these conventions out. It's not just a few kb. It makes it easier to organize code, determin semantically where a class belongs, and simplify autoloading. Additionally, for plugins, it makes it simpler to find and utilize plugin classes. So, yes, there are benefits, besides the obvious ones of fewer keystrokes.
As for breaking compatibility, this is part of the reason we are waiting to do the ZF migration to 5.3 until the 2.0 branch, which will be the first time we can break BC in our APIs. There are some other architectural places where we will want to make changes, so introducing namespaces at that time makes sense. "PHP developers will finally need to start thinking about sane standards"
Thats just not the PHP way... unfortunately. Well, that's a rather pessimistic view... especially considering projects like Horde, PEAR, Solar, and ZF have been providing public standards and practices for many years now...
Very true. However, standards are equally important in the average work place. I've only met one or two developer that follow standards strictly... Most tend to be hackers rather than coders.
Perhaps I'm just working in the wrong place. Understanding namespaces as some kind of "packages" there could be an issue with all the top-level classes like "Zend_View", "Zend_Form" an the like.
Defining, that all functionality that belongs to a component should reside under the same namespace, Zend_View would become Zend::View::View. Besides that this looks pretty ugly, the root ZF library folder would no be polluted anymore and all components would be in their own folders/namespaces. At first glance the "A" and "I" prefixes look awkward so that one might wonder what they mean. What about a more readable solution like "Zend::Controller::AbstractAction" and "Zend::View::ViewInterface"? Another issue are conventions for "using" those classes. Considering a class that uses the Http Request and Response object. use Zend::Controller::Request::Http as Http use Zend::Controller::Response::Http as Http won´t work. so you have to think about conventions for that case. Maybe: use Zend::Controller::Request::Http as HttpRequest use Zend::Controller::Response::Http as HttpResponse So, besides chosing proper names for the classes/namespaces itself, one must consider how to use/rename them. Apparently I'm not a big fan of the php namespaces. The namespace and class naming conventions (whatever they may look like) will lower readability and while creating and using classes you have to remember several rules, that may not be obvious. I find it a lot easier to understand and locate "Zend_Controller_Action_HelperBroker" than reading "HelperBroker" and looking at the "use" definition at the beginning to find out what namespace it is in. So I hope, that ZF will not enforce the use of namespaces in the future for that it does more harm than good. First, off, I want to refer to an earlier comment, where I note that this post was only to trigger discussion of naming conventions for abstract classes and interfaces when using namespacing; full migration of ZF to support packages is going to require many, many more changes to accomodate.
Second, the usage of 'I' as a prefix is prevalant in several other languages; adopting this standard would make for a familar bridge from those languages to PHP and vice versa. Naming of abstract classes is less cut-and-dried, and certainly up for debate; you're the second to suggest prefixing with the full word 'Abstract', and I can certainly see that argument. Third, regarding multiple namespaces with similarly used packages, the liklihood of using several of these together is slim, and when it happens, the best solution is to either not import a namespace or to import a level up -- 'use Zend::Controller' instead of 'use Zend::Controller::Request'. Finally, using namespaces will primarily benefit those who develop the actual framework and library code; only in a few cases will the end-user developer need to use namespaces within their own code. While I'd agree that a standard like IView might provide familiarity, I don't think it's consistent with naming standards in the rest of the framework, which tend to be a little more verbose for the purpose of clarity, which I agree with. Once a product gets to a certain point, you spend as much or more time reading it as writing it, and it should be as clear as possible at first glance for that reason. I like the 'Abstract' prefix and think that an accompanying 'Interface' prefix would be the way to go. Just my two cents.
Ps
I was agreeing with Marc Jakubowski, the way the comments have come out that isn't clear. Good to see this discussion opened. It would be nice to have a wide discussion resulting in a best practices document descriving uses and pitfalls. From reading the replies here there seem to be more 'problems' than I thought of and jumping right into namespaces without preparation and thought seems a very bad idea.
Agreed,
There needs to be something like that from the beginning before bad habits and initial mistakes take over. I find namespaces make readability worse. They also cause more problems than they solve.
In a multi programmer environment who wants to go looking up what the previous developer has chosen as an alias for the Zend::foo::bar group of objects when they could access the object directly. Also when you want to use an object in a namespace who want to go to the top of the page to add the use needed to use the "shorter" version of the class name. Namespaces are a nightmare I tried to use them and didn't see the advantage. With good coding standards (like those of ZendFameworks) we've never had a "namespace" clash of objects. without namespaces code is clear and stright forward, with namespaces code becomes confusing and troublesome. Ps
Matthew I sent you an email on Jun 25 about 5.3 and the goto keyword I've not heard anything back from you, have you received the email ok? Yes -- fix was slated for next mini release, and I actually fixed it in trunk and the release 1.5 branch today. (See ZF-3022 for details.)
We'll have to agree to disagree on this point. I've used packages, namespaces, and modules in perl, and always found it much easier to understand the code when using them. You have to train yourself to read the code slightly differently, but overall, the effect is more readable code, and better organized code.
As a middle ground between AAction and AbstractAction, I could see using AbstAction and ImplView. That's not a preference per se, just pointing out the option...
I'm not really up to speed on how namespaces will be implemented in PHP, so my next suggestion might be moot - What about stopping one class hierarchy above the one you are namespacing for?
Using your example: namespace Zend::Controller::Request class Http extends Abstract { } will change to: namespace Zend::Controller class Request_Http extends Request_Abstract { } I realize it might be at the cost of losing some minor convenience, but it's more readable (you can clearly see you extend an abstract request class). The problem with this approach is that you cannot then have the class in the same namespace. For instance, the desired namespace would be Zend::Controller::Request -- but with your approach, you'd have to use Zend::Controller to get to the classes you need. Additionally, it negates the possibility of encapuslating the entire component in a single directory tree.
Why does it negate using a single folder for the compnonent? It should resolve the same as before - using Zend::Controller namespace along with Request_Abstract should autoload a
Zend/Controller/Request/Asbtract.php file Okay, so not a problem of single folder, but single namespace. Zend::Controller:Request_Abstract would not be in the Zend::Controller::Request namespace, which will cause a semantic disconnect.
Yes, I agree it's less than perfect. It's a matter of personal preferences - do you rather lose using abstract / interface in the class name, replacing them with less intelligible I and A or having a less specific namespace?
Since so many people disagreed, I'd like to add a +1 for this idea.
Using IView or AView is common practice in other languages. And one of namespace's goal is to shorten identifiers without adding ambiguity. In this sense, simple, well know one-character prefixes seem a good idea to me. $viewRenderer = HelperBroker::getStaticHelper('viewRenderer');
could be used? (Assuming you've executed 'use Zend::Controller::Action;' somewhere earlier...) ITYM "use Zend::Controller::Action::HelperBroker;" Say we had..
{code} use Zend::Controller::Action; use Zend::Other::Namespace; $viewRenderer = HelperBroker::getStaticHelper('viewRenderer'); {/code} Then I'm guessing that it would use the HelperBroker from the Zend::Controller::Action namespace. What if one was then itroduction into the Zend::Other::Namespace at a later date? Wouldn't this cause alot of confusion or class name clashes? What would happen? Just another thought, but maybe there should only be one namespace, Zend and all classes should exist as classes under the one namespace e.g.
namespace Zend; class Controller_Request_Http extends Controller_Request_Abstract { } Having been thinking this over... You can still simply do:
use Zend; and then create your classes with Controller::Action::HelperBroker::getStaticHelper('viewRenderer'); I think it would be use as so...
{code} use Zend; Zend::Controller_Action_HelperBroker::getStaticHelper('viewRenderer'); {/code} Having a single namespace 'Zend' negates most of the benefits of using namespaces; having a separate namespace per component, and potentiall sub-component, can lead to shorter class names and references in the library code.
Not to mention better portability as your may want to import only part of Zend for example...
#13.1.1.1.1
Dougal
on
2008-07-02 11:30
(Reply)
Just to throw in my 2 cents...
I like the I prefix for interfaces and Abstract prefix for abstract classes: IView and AbstractView What just occurred to me... slapping Abstract in front of a class name does give a (potentially) long list of abstract classes in your autocompletion, forcing you to type out the word Abstract.
For this reason I'd like to suggest using ViewAbstract instead of AbstractView, although I like the former a bit better. An added advantage is that this is a smaller change from the current setup, so a lot of naming would look familiar. You did not inform me "what just occured to you" when we discussed this on IRC earlier!
However, yes; I find this a reasonable approach too. Using a single 'I' works for interfaces, but a single 'A' for abstract classes looks odd. +1 on IFoo and and BarAbstract Or how about ... we just get rid of OOP and go back to the good old days?
Matthew,
I agree I is OK for denoting Interfaces, I do not feel the same for A, Abstract nor Abstract. What about _. Just as an underscore is, by convention, used to name non-public methods and properties of classes, a class name prefixed by an underscore would denote a non instanceable class (ie. an abstract class). Would look something like this (if I understood the syntax): namespace Zend::View interface IView { // ... } abstract class _View implements IView { // ... } class MyView extends _View { // ... } Benefits: 1. Extends widely used naming conventions to a place where no code has gone before 2. As grep/find friendly as the current naming conventions. My 2 cents dude. This would mean that classes will not start with an uppercase letter, which is indeed a place where no code has gone before. I'm not entirely sure as to why this pseudo standard is prevalent, but not starting classes with an uppercase letter goes against "all" other languages.
Also, an underscore prefix is generally used to hint about visibility, and would be confusing for people thinking private classes are allowed in PHP. I'm considering changing my above-mentioned statement of suffixing class names with 'Abstract' to having no suffixes and prefixes for abstract classes at all. Can anyone explain to me why it is so useful to be able to grep for abstract classes? The problem I see with no prefixing/suffixing is that it would conflict with concrete implementations of that class in the same namespace, so we would have something like 'interface IView', 'abstract class View implementes IView', and 'class ViewImpl extends View'. Writing 'new ViewImpl()' is not as cool as writing 'new View()', though. Tradeoffs... The primary issue is keeping abstract classes and interfaces within the same namespace as the concrete implementations, plain and simple. I personally have no problem with using no notation at all -- so long as that goal can be met.
I seem to recall that .NET uses "Base" when naming Abstract classes? It's shorter than "Abstract", but clearer than just "A".
It also kinda suggests how that class should be used - as a "base" for more functionality. So instead of Zend_View_AView or Zend_View_AbstractView it would be Zend_View_ViewBase or Zend_View_BaseView? Not a bad idea.
I've had a lot of feedback on this issue. Some people are against using any sort of notations, and feel only generic names should be used -- Zend_View would be abstract, while Zend_View_Php, Zend_View_Smarty, and Zend_View_PhpTal would be concrete implementations. The problem with this is that the abstract class or interface is no longer in the same namespace as the concrete implementations. Which brings us back to having a name within the namespace to indicate the interface or abstract class. I'm leaning towards keeping the IFoo syntax for interfaces, as it's a common syntax across a number of languages, and utilizing either 'Base' or 'Abstract' as part of abstract class names, either as a prefix or suffix. Using it as a suffix appeals to me as it differentiates it from interfaces (which prefix). If a prefix/suffix has to be used for abstract classes, I'm leaning towards ClassnameBase, i.e. a 'Base' suffix.
Another option is to force concrete implementations to be suffixed with 'Impl' if they would conflict with the abstract definitions in the same namespace. It's not _that_ many places there would be a conflict, so it might work. However, "new Zend_ViewImpl()" looks a bit weird :p About the use of "Impl":
Could you give an example of a Zend Framework class where this would be required? I wouldn't recommend using abbreviations like “Impl” anyhow: or decide to use one-letter abbreviations or the full word. interface Zend_View_Interface
abstract class Zend_View_Abstract class Zend_View If those were to be renamed and be in the same namespace: interface Zend::View::IView abstract class Zend::View::View class Zend::View::ViewImpl Another possibility is to give the abstract class a prefix/suffix: interface Zend::View::IView abstract class Zend::View::ViewBase class Zend::View::View For the record, I don't like the 'Impl' suffix either. Another thing that looks likely to affect OOP libraries and frameworks is autoloading, specifically when using exceptions. For instance, consider this:
namespace Foo::Bar class Baz { public function status() { throw new Exception("This isn't what you think it is"); } } You'd expect the exception to be of class Foo::Bar::Exception, right? Wrong; it'll be a standard Exception. To get around this, you can do the following: namespace Foo::Bar class Baz { public function status() { throw new namespace::Exception("This is exactly what you think it is"); } } By using the namespace keyword, you're telling the PHP engine to explicitly use the Exception class from the current namespace. I also find this to be more semantically correct -- it's more explicit that you're throwing a particular type of exception, and makes it easy to find and replace these with alternate declarations at a later date. Mathew, You mentioned how to use proper namespace, but you didn't say how to declare a Exception in namespace where you extend Exception from global namespace or root namespace! (Overlapping names only) thank you! Easy -- just have it extend the global exception class:
namespace Foo; class Exception extends ::Exception {} I think, that Zend use too much complicated names and too much package. I think that it should more inspirated from Java frameworks. I think, that is better use
zend_controller_AbstractRequest instead of Zend_Controller_Request_Abstract Why Zend use upper case for package name? Well, you won't make many friends in PHP-land by telling them to emulate Java.
That said, my current thinking is to use names such as these: Zend_Controller_Request_Adapter (interface) and Zend_Controller_Request_Base. This gives a much better semantic meaning to the names and avoids any smell of reverse hungarian notation. As for why we use MixedCase, it's (a) easier to read, and (b) allows for multiple words per package segment, without confusion. Hi Matthew,
good that this discussion starts rolling! We (over at FLOW3 / TYPO3v5) switched to using namespaces last week, migrating all existing code in a three-day journey into namespace-land (http://forge.typo3.org/repositories/revision/packages/1210). Some notes (expect this to change and expand) are currently to be found at http://forge.typo3.org/wiki/flow3-overview/Notes_on_using_PHP_namespaces While we had no problems before with "emulating" namespaces in a similar way to ZF (using underscores and UpperCamelCase to build class names) we decided to go the "right" way of using namespaces. After all, we have been waiting for them to appear in PHP, right? While we need to search and find best practices for using namespaces, we also need support for them in our toolchain. What we saw already: * Zend Studio knows nothing about namespaces, this breaks syntax validation and auto completion. * phpDocumentor and Doxygen fail in dealing with namespaces. Pretty bad if you like documentation. * How do you refactor if global search and replace isn't an option anymore, because you have multiple Manager classes? We need serious refactoring tools - look at Smalltalk and Java. It might make sense to approach vendors and projects in some united way, to make sure they hear our voice! Karsten Hi again,
this time commenting on the remarks you had with respect to you "Exception" example. I tried it, and could not reproduce your described behaviour. Take this example code: --- file Baz.php -- namespace Foo::Bar; require('Exception.php'); class Baz { public function status() { throw new Exception("This isn't what you think it is"); } } $baz = new Baz; try { $baz->status(); } catch (Exception $e) { echo get_class($e); } --- end Baz.php -- --- file Exception.php -- namespace Foo::Bar; class Exception extends ::Exception {} --- end Exception.php -- calling "php Baz.php" tells me the exception thrown is of class "Foo::Bar::Exception". Even if I move the instantiation out of Baz.php into a third file and instantiate Foo::Bar::Baz it works. Tested with alpha1 and alpha2. Karsten PS: If Foo::Bar::Exception is not defined, it will of course fall back to the standard Exception. Maybe you missed that point? Happened to me when doing some other tests... Add Comment
|
Calendar
QuicksearchLinks
CategoriesSyndicate This BlogShow tagged entries |
|||||||||||||||||||||||||||||||||||||||||||||||||





© Giant Ginkgo Matthew Weier O’Phinney announced Zend’s naming scheme for the Zend Framework from the point where PHP 5.3 namespaces are used. The issue is, that the PHP parser does not allow class Abstract, neither interface Interface as
Tracked: Jun 30, 11:42
Over at Phly, boy, phly, Zend Framework coder Matthew Weier O’Phinney, talks about issues with implementation of namespacing in PHP 5.3 and the coding standards of Zend Framework ...
Tracked: Jun 30, 12:27
P?ed nedávnou dobou byla uvedena verze 1.6 Zend Frameworku, o které se ale te? zmi?ovat nechci. Je?t? p?edtím prob?hla na blogu jednoho z vývojá?? frameworku - Matthew Weier O'Phinneyho zpráva o tom, ?e ve mezi vývojá?i Zend Frameworku se za?íná diskutovat o podpo?e jmenných prostor?, které jsou nov? v php 5.3. Nic není úpln? jisté, ale ur?itá mo?nost se tu rýsu
Tracked: Sep 13, 09:56