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?

Hi. I'm Victor Nicollet,
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!
@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 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?
@Matthew Turland: if there is, I’d be glad to hear about it!
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.
@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
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.
@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.
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;
@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.
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…
@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!
At first I was thinking this was just another Zend bashing article, but in the end I agreed with everything you said. However, here are ways you can solve your problems that you may have not considered.
The DB Table Gateway pattern provides an intermediary layer of Value Objects which have the desired class properties which will get filled in by the Zend_Db_Table layer. Granted, it’s an added piece of complexity, but definately a useful one. I use a code generator to generate all the Data Access code based on Zend_DB_Table and value objects.
The other technique that I can see beneficial is typed view classes that extend from Zend_View. Thus, instead of using a generic view, you use Account_View which has properties for the data the view will use. This increases the self documenting nature of code as well.
You could also add exceptions to the view rendering method that will catch missing (required) properties. For example, it should be an exception to try to render an AccountDetailView without an accountDetail property set.
Your arguments about Zend_View’s OOP aspects are based on a misinterpretation of their poorly worded paragraph. Their intention was to point out that with Zend_View, your templating system works with actual values, and objects. Where as the older template paradigm was to parse scripts for keywords and replace them with values. SurviveTheDeepend’s point is purely that you deal with native php in the view files instead of a second level template scripting language that is parsed and processed separately.
“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. ”
A view’s job is to display data in a way that it sees fit, but it relies on something else to PROVIDE data–the model.
The model’s job is to collect, managed, and operate on data, and more importantly provide access to data. But it has no ability to display it.
The controller’s job is the match maker, because as good as a model is a providing data and as good as a view is at displaying data, neither work unless paired together.
Your code example shows working directly with the View class and setting a variable on the view instance. Ultimately that’s how you pass data to the view sure, but that’s not how the view is “implemented”. The implementation is pairing the view with the data. If you want an implementation that you can reuse, then you need to code in away that allows for that.
For example, lets say you want a book rating module. Obviously the view is responsible for the HTML and how the data is displayed, but ultimately the goal is to display the book title, author and rating. The view that renders this info is a view whose soul purpose is to display book ratings. Not car models, not user info, book ratings. So whenever and where ever you want to use it, you’ll some how need to provide it that basic data. There is an implicit requirement to know what a view is displaying. There’s no avoiding that fact. However, you can make an implementation that addresses that flaw. You can extend Zend_View and call it Zend_View_BookRating. Give Zend_View_BookRating a validation method that runs before render (override render to call the validator prior to super()). The validation method checks if the view has been paired with a data model. If not, it throws an exception. Give it another functions called setBookRating, that expects a BookRatingModel object. Now, in order to “reuse” the book rating review, you’d use the following code.
$view = new Zend_View_BookRating();// for simplicity, the extended view defines the correct view script internally
$view->setBookRating(new BookRatingModel(‘Moby Dick’));
Now, you can use and reuse your book rating view when and where ever you want. During development, when you are adding book rating modules all over your layouts and sublayouts, if you forget to provide it a book rating model, you’ll get an exception and the exception will tell you you forgot to pass it a book rating.
Jeremy,
Thank you for your analysis. I agree with your remarks, since for the most part it’s what I ended up doing (although I thoroughly streamlined it by merging the PHTML into the class definition itself so that the type of $this in the view script would be known, and also avoding having two files for the same thing).
My point was, mostly, that this is not what the Zend Framework documentation advocates, nor did the latest developments at the time my article was written point in any other direction- Zend_View (and instances thereof) certainly looked like it was intended to represent the rendering system, not the thing being rendered (and this, in a sense, is perhaps better: you would use a Zend_View through composition, thus allowing your classes to inherit correctly from other things).
Now, of course, these days my code looks more like
let rating = M.Book.Rating.get “Moby Dick” in
V.Book.Rating.render ~rating ~i18n
…