Tag Archive for 'Zend'

Frameworks, Libraries, Conventions

Funkatron came up with the MicroPHP Manifesto :

I am a PHP developer

  • I am not a Zend Framework or Symfony or CakePHP developer
  • I think PHP is complicated enough

I like building small things

  • I like building small things with simple purposes
  • I like to make things that solve problems
  • I like building small things that work together to solve larger problems

I want less code, not more

  • I want to write less code, not more
  • I want to manage less code, not more
  • I want to support less code, not more
  • I need to justify every piece of code I add to a project

I like simple, readable code

  • I want to write code that is easily understood
  • I want code that is easily verifiable

Without surprise, a large swath of the community did not take it well, for similar reasons to my earlier piece against Zend Framework — deviation from the commonly accepted norm.

I have come a long way since I wrote that article, and I must have been walking in circles, because I actually ended up where I originally begun : why do we call these things frameworks ?

Zend, Symfony, CakePHP — as well as Node.js, Rails, Django, Ocsigen … — actually contribute three different things to projects that use them.

Libraries

A library provides functionality used for solving general problems in a flexible, standalone manner. Zend_Mail is a classic example of the library aspect of Zend Framework: you can plug it into your application and start sending e-mail. The interface you would use is uncluttered by details that are not directly related to sending e-mail.

The core qualities of a library are its power (how many different aspects of a problem does it let me solve — attachments, rich text, bouncing, MIME handling…) and the clarity of its interface. What problems can you solve, and how fast can you solve them?

Conventions

When you hear «conventions» you immediately think of opening brace positions and variable naming rules. It’s about more than that.

The Model-View-Controller separation is an example of convention: it has been decided that under no circumstances should HTML rendering occur in Model code, no HTTP or session handling should happen in View code, and no SQL queries happen in Controller code.

Good conventions are designed to let the developers assume interesting properties about the code without having to actually read it. A convention like «no global variables» means I never have to care about global state in my code, ever. A convention like «view code must respect the law of Demeter» means all the data used by the view is right where it is being initialized.

They are also designed to make reuse and interoperability easier by reducing the number of ways in which a possible interface can be implemented. A convention could say the values are passed by assigning them to members post-construction and not as constructor arguments, so you have one less point of contention between the object that is initialized and the object that does the initialization.

Last but not least, conventions are usually based on experience of things that could go wrong if certain behavior is allowed. A typical example is the requirement to escape all strings as they are being output — eliminating any ambiguities as to whether the string has already been escaped elsewhere and should be output as-is: it has not.

Zend comes with a variety of useful conventions enforced both through the interface of its tools — this is how you use a view, this is how you define a view helper that should be available from within any view, this is how you bind a piece of code to an URL, and so on. I happen to disagree with many of those conventions myself — because I believe they solve the wrong problems — but they are certainly better than a project with no conventions.

For the reference, my PHP conventions are described in the user manual for Ohm.

Framework

A framework is actually going a step further than mere conventions. They are super-conventions designed to be respected by plugin authors. The point is that if plugin A and plugin B respect the set of conventions provided by the framework, then they can be used together in the same application.

Consider a practical example : a plugin that implements a CAPTCHA field in a form, and a plugin that displays and submits a form through AJAX. On a bad day, it goes like this :

  1. When an error occurs, the server-side AJAX-form plugin sends out a small piece of JSON containing the fields that have errors, along with the error messages. A small client-side script applies these.
  2. However, the CAPTCHA plugin expected the image to be reloaded when an error occurs.  It may either keep the same image and target word — defeating the purpose of a CAPTCHA — or change the target word without knowing that the image could not be changed.
  3. You then need to post on StackOverflow hoping for a solution, search online for a patch to either plugin that could make it work as expected, or try to read the code to either in order to create the patch yourself.

Had the framework provided a clean notion of « this field must be refreshed on every attempt » as part of their form interface, both plugins would have used it — the CAPTCHA plugin would have marked its field as such, and the AJAX plugin would have implemented a special case for such fields.

As such, the purpose of a framework is to provide a clean, unambigous and extensive vocabulary that all the plugins should be able to speak, and that is designed to cover as much real-world situations as possible.

Zend Framework and Symfony in particular do an absolutely great job of this. When you can have a pager component push its data to the page through a progressive enhancement component, and log its performance to FirePHP when an user authentication component  determines that the viewing user is a developer, and all of it works by plugging square pegs into square holes, you know there has been a lot of great work going on below the hood.

Back to the point

Using a framework is all fun and games until you need to disagree with it. You need to plug out what does not work, and plug your own implementation in its place. The more complex the vocabulary, and the harder it will be to write new code — frameworks make it easy to connect existing components, at the cost of having to deal with more concepts when actually implementing new things.

What it boils down to, in the end, is whether you expect to be reusing a lot of third party components, or to write a lot of your own code. In the latter case, MicroPHP — and lean environments that do not have a heavy framework side to them — is actually an improvement over trying to fit a six-inch wooden square peg into a mini-USB port.

The exception to this is, of course, being so familiar with a particular framework that you immediately know what changes you need to do without fighting against third party code.

Why I Gave Up on the Zend Framework

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.

We are Zend. Resistance is futile.

We are Zend. Resistance is futile.

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_View templating 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 current Zend_View instance. 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:

  1. one less round-trip to the database documentation
  2. zero chances of typing $account->firstName by mistake
  3. 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?

PHP Autoloading

Like C, PHP initially started out as a “every file defines functions and variables and classes” language where using an entity assumed that it had already been defined (which, in practice, meant that the file it was defined in had already been included).

This led to several issues :

  • It was hard to find out what file contained what function. It was certainly possible to namespace functions based on the file name, but it required more effort than the amateur team workforce was capable of, and it made function names so much longer.
  • It was easy to mess things up when doing dynamic loading, because one could mistakenly load a dangerous or private file.
  • When serializing classes, one would have to determine where the class was defined when reloading the serialized data, so that the class definition could be loaded again.
  • Every time a class or function was used, the developer would have to check that the corresponding definition file was loaded as well. This led to loading many files that were not necessary just in case they would be used. Since PHP is not compiled, this meant parsing the files and populating the global scope with unnecessary entities.

Which is why autoloading was introduced.

The mechanism behind autoloading is simple : if at any point during the execution of a program the script uses a class that is not defined, the __autoload function is called with the name of that class as an argument. That function is then allowed to load a file or evaluate a script string in order to define that class.

The function obviously determines, using the class name, what source file defines that class, and loads it just in time for the class to be used. This solves all of the above issues in one strike:

  • There’s usually a clean convention for mapping class names to files. For instance, the Zend convention is that class Foo_Bar_Qux is defined in Foo/Bar/Qux.php within the include path. And if you don’t follow the convention, the code doesn’t work (of course, there’s still the issue of writing the code on Windows and then running into Linux case sensitivity).
  • Using Zend_Loader (or writing your own sane __autoload function) you can restrict dynamic loading to a single directory.
  • __autoload also triggers while deserializing.
  • Developers don’t need to include anything : every used class is included, and no class is included unless it’s used.

There is of course a slight performance penalty as the loader has to process the class name to find out what file to load, but bytecode caches work around this issue quite well when performance is important.

Zend Controllers

The Zend Framework dispatches the provided URL to a controller action which reacts to that URL. The standard dispatch rules can be summarized as follows:

  1. The dispatcher examines the first segment of the URL and matches it against the names of the registered modules. Note that a default module may be used if no other module matches.
  2. The dispatcher then examines the next segment of the URL and matches it against the names of the controllers available in the directory bound to the module. So, if the segment is auth, it will look for a file named AuthController.php. By default, if there is no match, the IndexController.php file may be used (if it exists).
  3. The dispatcher then examines yet another segment of the URL and matches it against the names of the actions available in the controller class. So, if the segment is logout, it will look for a method named logoutAction. By default, if there is no matching, the indexAction may be used (if it exists).
  4. Any remaining parts of the URL are provided to the selected action.

So, basically, the initial configuration of the Zend Dispatcher will generate a set of URL prefixes which are bound to member functions of fresh instances of classes in the file system. This leads to the obvious question: what is that set of prefixes for my website?

In my case, the list would be:

-- module 'admin'
  -- controller 'auth'
    /admin/auth
    /admin/auth/logout
  -- controller 'help'
    /admin/help/page
  -- controller 'index'
    /admin/
  -- controller 'pages'
    /admin/pages
    /admin/pages/page
    /admin/pages/save
    /admin/pages/ajaxmove
    /admin/pages/ajaxrename
    /admin/pages/ajaxdelete
    /admin/pages/ajaxnew
  -- controller 'users'
    /admin/users
    /admin/users/ajaxnew
    /admin/users/ajaxdelete
    /admin/users/ajaxupdate
-- module 'public'
  -- controller 'index'
    /

So, for instance, /admin/pages/page/id/1 would forward /id/1 to the page action of the pages controller of the admin module, whereas /home/about-us would forward /home/about-us to the index action of the index controller of the public module (which is the default module).

The Tool

The above list was automatically generated by a tool. The core of that tool is this:

class _privateControllerExplorer {
  function __construct($modules, $default_module) {
    $this -> _modules = $modules;
    $this -> _default_module = $default_module;
  } 

  function explore($root_path) {
    $modules = array();
    foreach ($this -> _modules as $name => $path)
      $modules[$name] =
        array( "path" => $root_path . $path,
               "controllers" => $this -> explore_module($root_path . $path, $name));
    return $modules;
  } 

  private function explore_module($path, $module) {
    $uri = $module == $this -> _default_module ? '/' : "/$module/";
    $controllers = array();
    foreach (glob("$path/*Controller.php") as $controller) {
        $name = basename($controller);
        $name = str_replace('Controller.php', '', $name);
        $name{0} = strtolower($name{0});
        $controller_uri = $name === 'index' ? $uri : "$uri$name";
        $controllers[$name] =
          array( "path" => $controller,
                 "actions" => $this -> explore_controller($controller, $controller_uri));
      }
    return $controllers;
  } 

  private function explore_controller($path, $uri) {
    preg_match_all('%function[^a-zA-Z0-9_{]*([a-zA-Z0-9_]*)Action%',
                   @file_get_contents($path), $matches);
    $actions = array();
    foreach($matches[1] as $action)
      $actions[$action] = $uri . ($action == 'index' ? '' : '/' . $action);
    return $actions;
  }
} 

function explore_controllers($modules, $default_module, $root) {
  $explorer = new _privateControllerExplorer($modules, $default_module);
  return $explorer -> explore($root);
}

One should call the function defined at the bottom using the arguments:

  • The modules are a hash binding every module name to a directory where the controllers for that module are to be found. This is usually extracted quite easily from the configuration of your FrontController (where controller directories are bound to module names).
  • The default_module is the name of the default module (or null if there is no default module). This can also be found in the configuration of the FrontController.
  • The root is the absolute path to the position from where the controller directories are defined. That is, controller directories are assumed to be relative paths, and must be completed with the root path.

It should be fairly trivial to write a function which extracts that information from the FrontController.

The tool obviously makes a few assumptions. The first assumption is that the standard Zend dispatcher is used (otherwise, the rules for dispatching may not match what the tool is attempting to extract). The second assumption is that every controller file has a fairly simple layout : instead of intrusively interpreting the file in PHP (which may require the inclusion of other files and have side-effects) the tool merely processes it with a regular expression that could definitely use some improvement.



1170 feed subscribers
(readers who polled a feed this week)