Thoughts on Frameworks
This post was the natural evolution of an old post, Thoughts on CakePHP. My experience with frameworks has mostly been in CakePHP, Kohana, and Pylons.
Routing on Conditions, Building Blocks for Abstracting REST
I’ve found a lot of documentation in PHP gloss over routing and the idea behind REST. Rails’s documentation does a much better job hammering it in.
function create()
{
if(is_post())
{
// create post
}
// load post
}
The above should be two methods: create and new
def create(self):
// create post
def new(self):
// load post
But the URI resource between both options should be the same. That is, the POST is handled in the route itself: map.connect('/posts/create', controller='posts', action='new', conditions=dict(method='POST')) map.connect('/posts/create', controller='posts', action='create')
The next logical step is to add more conditions in the routing logic keeping your URI resources clean without making the actions complicated. This is important because implementing REST on standard web forms is typically done using a hidden input element. In order to make this easier on the developer, logic needs to be in both the form generator and the routing code to create and handle requests other than POST or GET (i.e. PUT and DELETE).
Extending Core Files
I have moments where I want to extend core functionality. I haven’t had this issue much with Pylons and I think this is because the way Python deals with importing files and namespacing is very clean. This allowed Pylons to stay out of the way when adding custom functionality.
Kohana also does a decent job. Every core class is a bare class that extends a Kohana specific core class. The ORM looks like this:
class ORM extends Kohana_ORM
{}
If I wanted to add a method, I would simply create a new ORM class in my application:
class ORM extends My_ORM
{}
class My_ORM extends Kohana_ORM
{
function my_orm_custom_function() {}
}
In Kohana, any class dropped in the application folder overrides the same class in the system folder, and this process is consistent.
CakePHP has a similar hierarchal concept but it’s less generic. Only certain classes are expected to be extended, such as AppController for Controller. There are specific locations in the filesystem Cake checks, and it’s somewhat dependent on the type of file being loaded. The experience is less consistent.
Namespaces and Automagic Objects
Most frameworks use a class with static methods and the factory pattern when a specific object instance is needed. Everything is kept decoupled.
I believe CakePHP automatically binds objects in an effort to reduce the usage of globals. I have no problems with globals in my controller actions, because I see their primary job as connecting various components together. Cake also has issues with keeping this namespace clean. Both models and components are bound to the same namespace in the controller and leads to ambiguous cases when the class names are the same.
I especially dislike the strategy as applied to models. One of the difficulties with dealing with model objects is determining the state of the object. By only having one model object available (I do realize a user can manually instantiate new model objects but that seems to be circumventing the Cake way), the task of tracking the state of the object becomes more difficult. If I took a code snippet in the middle of the action with a Model->save call, I can’t tell if the save will update the record or create a new one. In a different framework, if I couldn’t tell, I can get around the ambiguity by instantiating a new model object prior to the save call.
Models Returning Objects
CakePHP is the only framework I’m familiar with that returns queries as arrays instead of objects. The benefit of this approach is after the resulting query, you’re dealing with pure data instead of an object. Objects can be a little tricky because they can end up in different states, especially if they’re extended with functions that alter itself. A developer has to keep better track of objects. With this in mind, it seems like Cake’s argument to return data and process it in the helpers is a good one, but I just prefer having the ability to extend the model itself.
blog comments powered by Disqus