The Zend Framework is a really nifty thing. Really, it is. The amount of functionality that you get merely by installing it is extremely exciting: internationalization, forms, an MVC layout for your program, a cute class loader, a database abstraction layer, a templating engine, a request dispatcher, mail-sending functions, pretty debugging “dump” functions… and there are so many people working on it and using it that basically all the bugs left in there are shallow. It has been a staple dependency of many of my projects for quite a while now, and still is.
Zend Framework is actually available for your projects in two flavors, «use what you need» and «obey the hive mind», with a continuous spectrum in-between these two extremes.
The «use what you need» approach leaves the maintenance programmers with a warm and fuzzy feeling. All you have to do is dump all the framework files somewhere in your include path, include the files for the bits you want to use, and just call the functions. The framework takes care of recursively including the appropriate dependencies for you and carefully avoids treading on any toes by prefixing everything with «Zend».
In fact, if you use Zend_Loader, you can skip the include-source-files step completely (except for Zend/Loader.php obviously), and since auto-loading is reverse-compatible with loading files manually, it’s also a good step towards a well-deserved refactoring.
So, if you need to send multi-part mail, with HTML-and-text content, in UTF-8 format, you can just use Zend_Mail and everything will work fine regardless of the rest of the code base. There are dozens of such small features (for PDF generation, LDAP, access control, localization, and so on).
There is virtually no excuse for not using a plug-in class from the Zend Framework in your application if it solves the problem you’re having. Besides, since the files are not included until you need them, the worst that could happen is that you’re having some PHP code taking up a few megabytes of disk storage for nothing. So I have a lib/Zend directory on all my projects, just in case I need something.
Obey the Hive Mind
While many pieces of Zend are independent of each other, there’s a central functionality core that’s designed to act well together. There are many examples:
- it’s easier to use Zend_Dispatcher and Zend_Controller together.
- it’s easier to render a Zend_View if you’re also using Zend_Controller.
- it’s easier to turn a Zend_Form into HTML if you’re using Zend_View.
- it’s easier to set up a “login already in use” validator with Zend_Form if you have a field in a Zend_Db_Table to connect it to.
- it’s easier to translate Zend_Form error messages with Zend_Translate (and Zend_Registry).
Sure, it’s usually possible to take advantage of 99% of the functionality without having to add new dependencies, but there’s always that tiny voice in the back of your head, nagging that you could get that additional 1% so easily if you just gave in.
Giving in means, of course, going all the way to Bootstrap heaven: now your project is laid out across the lines of the ideal Zend Framework template, your files cleanly stashed in their folders with a cosmic Feng Shui feeling to it all, and the Zend approach to MVC pervades your every HTTP request.
This isn’t so bad: actually, such an approach has some huge selling points for shops that write lots of small projects, such as the ability to get 20% of your basic functionality up and running in days, the ability to hire any Zend-certified developer and not have to educate them about the framework, and you don’t need them lousy architects on your team.
I’ve had some trouble with the Zend way before, though. There are some bits of functionality that I won’t touch with a ten-foot-pole, such as Zend_View, Zend_Controller or Zend_Db_Table, because the havoc they wreak in situations I find myself in outweighs the benefit.
Documentation
My main issue is that I find Zend quite lacking on the documentation side.
«But the Zend Framework is possibly the most documented there is!» you say, before trailing off in a rant about how the “FM” should be “R” and the “FW” should be “S”.
You’re probably right. But I don’t really care about that documentation. I’m talking about project documentation—to know what happens in code written by my team.
«What does Zend have to do with that? Document your code, you lazy slob!»
Humans are lazy, and I would argue that laziness is actually an essential quality of a good programmer. I can require that documentation be written, but I expect it to be missing, inaccurate or monosyllabic. Things like that happen when you’re rushing out a bug patch at 3:00 am. And even if I could ensure that documentation is written and kept up to date, I’d rather have my code be self-documented—not only does it take less time, but it’s harder to get inaccurate self-documentation and you can even get the language to check things for you.
It’s the difference between documenting the parameter type as a @param MyClass $obj in a comment and documenting it as a MyClass $obj type hint in the function signature.
Look at the average .phtml template, and you’ll see something like this:
<div>
...
<a href="<?php echo $this->getUrl() ?>"><?php
echo $this->escape($this->user->name)
?></a>
...
<?echo $this->partial('preferences.phtml', $this->pref); ?>
...
</div>
Half the point of a view in the MVC approach is that I should be able to easily reuse that view from any controller, or even from within another view. Of course, Zend lets me do this very easily:
$view = new Zend_View();
$view->xxx = yyy; // Fill in members
$view->render('template.phtml');
The red line, of course, is where trouble begins. Since Zend_View fields are by definition dynamic, there’s no way to get auto-completion to help you find what they should be. Nor can you look at a list of these fields in a class definition or function definition, because there’s none. You have to read the template file and find out by yourself what values are used by the template and what their types should be. Oh, and if the template passes some of that data to other templates, you have to read those templates too, because they might use specific information. And you have to look at view helpers too, because they might be accessing view elements behind your back.
Your best bet is to look at an existing controller that uses the view, and hope that you don’t stray too far from what that controller is doing. You never know: a certain member might be expected to be present if another has a certain value (this never happened with the first controller, but it happens in yours), there’s no compiler checking that all values are being provided appropriately, and runtime testing doesn’t reveal such special cases on the first try.
And they say Zend_View is an object-oriented approach to rendering…
The most important aspect of
Zend_Viewtemplating is that it is object oriented. You may use absolutely any value type in a template: arrays, scalars, objects and even PHP resources. There is no intermediary tag system between you and the full power of PHP. Part of this OOP approach is that all templates are effectively executed within the variable scope of the currentZend_Viewinstance. To explain this consider the following template.
That’s not what object-oriented means. OOP means if two views behave differently, then they should be instances of different classes, instead of injecting arbitrary code and data into a single class and spitting in the face of encapsulation.
The bottom line is that reusing Zend_View templates is a pain in the derrière unless you take special steps about it (steps that you wouldn’t need with a standard class-with-members).
What’s in that row?
This is futher compounded by the way Zend_Db works: an ORM that generates SQL from a sequence of PHP calls, and then turns the result into a list of Zend_Db_Table_Row objects. Which leads to the question of what fields can be found in a given row, and that question is hard to answer.
A typical application will follow a rule along the lines of «every table row is, by definition, a row of a table, so you just peek at the table definition and you know that each column is mapped to a field,» and that is a fine rule to follow, because then the only issue is you can’t type-hint the row based on the table, so you can’t make sure a given argument is always a row from “account”.
But following that rule is hard. In addition to those 80% plain old CRUD cases where you’re working with a single table at once, you’ll have those 20% that use joins where you need data from both tables (never mind the pain of doing that in PHP). Then you end up with a row that breaks the rule, so you keep it in tightly enclosed areas of your application, until it gets too frustrating not being able to use a view-that-renders-accounts on a record-that-contains-accounts-and-sessions, and the next thing you remember is that you don’t know if a given view expects an account or an account-and-session.
And the language can’t help you.
Auto-complete me
Nor can your editor, for that matter, since auto-completing $row-> requires knowledge that your editor simply cannot have (the list of columns defined when you configured your Zend_Db_Table).
I really do enjoy it when my code editor helps eliminate some of the tedium of writing code. In fact, I’m quite ready to make a small additional effort tagging my members, arguments and functions with some type information just so that writing code can be easier.
My editor is Eclipse PDT. It has several nice features that I use extensively.
The first is, of course, its ability to suggest members of classes and objects. Having well-defined classes to represent your data means that Eclipse can use the type hints you leave around to determine that $account is of class Account, so that it has a $firstname member. That’s:
- one less round-trip to the database documentation
- zero chances of typing $account->firstName by mistake
- being told immediately if $account has entirely different members (because it’s another type)
Since Zend_Db_Table_Row and Zend_View actually go out of their way to make sure that you can have arbitrary data in there based on runtime considerations, getting this functionality out of them is impossible.
The other nice feature I use a lot is the ability to control-click a class or function to see its definition. This lets me navigate around the code in seconds instead of having to open the project file explorer, expand several layers of directories usually far from each other, and spend precious brain power translating a class/member naming scheme into file naming schemes.
Finding a file is a job for the editor, not for the programmer.
My view helpers look like this:
View_Account::renderSimple($account);
Clicking on that function name brings up the file and scrolls it down to where it matters. Took me less than a second. Zend View Helpers look like this:
$this->renderSimpleAccount($account);
I dare anyone to navigate to the definition of that helper in less than a second. [EDIT: apparently I shouldn't dare people on the internets
]
What about links? The typical approach to generating a link to a different part of a site, with the Zend Framework, is to spell out its controller and action:
<a href="<?php echo $this->url(array( 'controller' => 'user', 'action' => 'edit', 'id' => '123' ));?>">click me!</a>
Now you have to click on every single URL on your website to make sure links are correct and you still manage to forget one and the end user will click on that link that’s spelled out as «edti». And even if you do get it right, you still have to navigate to the appropriate controller class, open it up and scroll down the right action.
My urls look like this:
<a href="<?=Action_User_Edit::url(123)?>">click me!</a>
Since every one of my actions is a class (as opposed to a function in a controller class), they get to have members, and one of these members is a static url() function that:
- lets me ctrl-click through to the action itself
- has PHP check that my link is correct (or else, die with a class-not-found answer)
- documents the expected URL arguments as function arguments
- even lets me find out who links to a certain controller, in case I have to move it
The bottom line…
…is that I don’t use Zend_View, Zend_Controller or Zend_Db in my projects. I need my code to be self-documenting, and there’s nothing self-documenting about Zend_View or Zend_Db. I need my code to be easy to navigate through and simple enough for my editor to handle, and the full dynamic behavior of Zend_View and Zend_Db prevent that.
Your needs might be different. Are they?

Some very good points, made very well.
Hopefully many of these points are to be addressed in 2.0 though, so I hope you do take a look once its out!
I must admit that, from my perspective, this blog post begs a question: if code using ZF isn’t optimally self-documenting, is there a specific framework already out there that is better in that respect?
Of all the warts the Zend Framework MVC stack has (ActionStack, Zend_Rest_Route), you have a beef with Zend_View and Zend_Controller? It sounds like the issue is you have a problem developing without a crutch, your IDE. I’m not a CLI-purist/anti-IDE nazi, but until I see Visual Studio for PHP that runs on Linux and OSX I’ll stick to using vim and Textmate. I have amazing productivity and so does my team; none of use crutches.
Seems like your problem with Zend Framework is more of a problem with certain design patterns and not so much with the framework. The truth of the matter since php is a loosely typed language you will not get much of the ‘autocompletion’ magic you are looking for and you may need to face the fact that php is not the language for you. I assume you singled out ZF because of it’s high visibility and your personal experiences with it but a lot of the points you made can be made for every other php framework out there.
@Dave: I am significantly more productive with Eclipse + PDT than I am with emacs. Tried both and found out I spend a lot of time just navigating my files when using emacs, so I’m now using Eclipse + PDT exclusively. I was an emacs fan from the beginning, but now that I started using Eclipse + PDT I wouldn’t go back for anything larger than a few pages. And to clear up that “Linux and OSX” thing, I’m working on Debian Linux right now
@brandon: There’s more to a language than just ‘autocompletion’. In fact, it ranks quite low among the features I enjoy in a language. If anything, I’d rather leave PHP because of its lack of closures (solved in 5.3, I know). But there are other reasons to use it, some of them objective (it’s well-supported and supports many things) and some subjective (I’m good at it, so is my team, java is for quiche eaters…) so I’m going to stick with it. Still, if getting ‘autocompletion’ is cheaper than what I get from it, I’m certainly paying. Pervasive use of some Zend components (and, indeed, design patterns based on __get and __call) increases that cost, so there’s a choice to be made there.
@Matthew Turland: if there is, I’d be glad to hear about it!
@Ryan: I certainly didn’t throw out ZF, it’s too diverse and versatile to be thrown out on a whim because I don’t like two or three components. I will be using 2.0 the day it comes out. With great care.
I think symfony would be a better fit for you if you want those things
Or wait for zend framework (with doctrine) 2.0.
I like that i can “assume” when i code. That way when i code i can assume that i have a username in a user table and by that definition be able to say $model = new Service_User(); $model->findById(42); $model->getUsername(); or $model->username;
Some tips and tricks when using PDT with Zend Framework that make my life easier:
With Zend_Db_Table, you can use the @property docblock element to document the fields:
/**
* $property string $username
* $property string $password
*/
class Application_Model_User extends Zend_Db_Table_Row_Abstact
{
}
Autocomplete on Application_Model_User objects will now work.
For documenting the fields used in a Zend_View view script, you can do this at the top of the .phtml file:
$user = $this->user; /* @var $user Application_Model_User */
$page = $this->page; /* @var $user Application_Model_Page */
etc…
Now you know all the view properties used and autocomplete works within the rest of the .phtml file
Whilst you can’t cmd+click on view helpers in view scripts,you can take advantage of PDT’s “Open Method” feature. Simply select the method name and then press shift+cmd+m. The “Open Method” dialog appears and usually the view helper is selected as the first item. Just press return to go directly to the code for that view helper. I just tested here and I can do it in much less than a second.
I find that PDT’s “Open Resource” (shift+cmd+r) also works well there is a one-to-one mapping for view helper methods to file name.
Using Open Type (shift+cmd+t), you can also jump to classes easily. e.g. I regularly do shift+cmd+t followed by “*Model_” and I get a list of all my models and can jump to the one I want using the down arrow key and then return.
These tips obviously work with all frameworks and any PHP coding
Regards,
Rob…
@christian: assumptions are often very useful, and often wrong. I don’t mind assuming lots of things in my code, as long as I have a safety net that tells me something went wrong. Unit tests do this. A static type system does this. Even a feeble attempt at hungarian notation does! With all the interesting feedback I hear, I should really try to look at Symfony again.
I do enjoy it too when I have a ‘usr_name’ in a user table, and I can say $user = User::get(42); echo $user->name; but writing that var $name; in the User class (or, even better, generating it from the database schema) is even better: not only does my IDE help me not mess up the variable name, but I don’t have to go peek at the user table to remember whether it’s a name, firstName or firstname.
@Rob: very interesting. Open Resource relying on that probable one-to-one mapping is nice. This does eliminate some of my issues.
For your Zend_Db_Table_Row attributes problem. You can easily extend the class so that it tries to populate class members if present and falls back to $_data array as last resort. Same for reading. Then extend your My_Row_User from this class and add member variables like My_Row_User::$username, $password, etc. Than set the class as Zend_Db_Table::$_rowClass, sit back and enjoy.
That’s the beauty of ZF. If you want it, be sure that there is a way how to do it.
Hi Victor, thanks for the link back to my article about problems with database abstraction.
I’ve been using components from ZF for several months, but only just recently began to dig into actually developing a ZF MVC app. One of the problems I’m having in the beginning is simply wrapping my brain around all the complexity, some of which seems overwrought.
I am not terribly thrilled with Zend_View myself. It seems like we get perilously close to violating the MVC separation of concerns in some of the .phtml files…
Views and autocompletion – the problem (no autocompletion in template.phtml):
$view = new Zend_View();
$view->xxx = yyy; // Fill in members
$view->render(’template.phtml’);
Views and Autocompletion – maybe a solution. It worked for me in MVC usage of ZF. phpDoc in the view script is necessary as mentioned in other answers.
class MyView extends Zend_View {
public $xxx;
}
$view = new MyView(’Specify views directory here’);
$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(’viewRenderer’);
$viewRenderer->setView($view);
$view->xxx = yyy; // Fill in members
$view->render(’template.phtml’);
I have to state, you chose your words well. The ideas you wrote on your encounters are well placed. This is an incredible blog!