views:

261

answers:

6

Let's say I have a PHP Model-View-Controller framework that maps an address like http://site.com/admin/posts/edit/5 to an action that looks like

Posts_Controller::editAction($id)

in file /admin/controllers/posts.php

Now, many existing PHP frameworks that I've looked at would accomplish this by something similar to

$module = Router::getModule(); // "admin"
$controller = Router::getController(); // "posts"
$action = Router::getAction(); // "edit"
$params = Router::getParams(); // array(5)

$controller_file = "/".$module."/controllers/".$controller.".php";
$controller_classname = ucfirst($controller)."_Controller";
$method = $action."Action";

require_once $controller_file;
$controller_obj = new $controller_classname();
call_user_func_array(array($controller_obj,$method),$params);

To me, this smells bad and seems too "magical": I don't believe that you should be able to dynamically create classes based off of a string, then call methods on it specified as strings.

I have also seen alternatives that use reflection to call actions, which also smells bad.

Now imagine I have a larger, modular CMS built off of a similar MVC framework that has a table in the DB for each "page" type: blog, static, photo-album, etc... I imagine that the implementation for this is similar to my previous example.

Am I the only one who thinks this is bad? If not, shouldn't there be a design pattern that would cover this situation?

To Clarify:

Is there some good way to map a query containing information about module, controller, action, and parameters into

  1. A file to include
  2. A class to instantiate
  3. A method to call'

That uses as little "magic" (string-to-class or -to-method or reflection) as possible?

Even better: how would this be done in C# or Java, without reflection? I can allow for concatenating strings to arrive at a file location.

+5  A: 

This would be handled by some sort of factory pattern, PHP just makes some nice syntactic sugar to avoid all the implementation around the factory pattern. I don't think this is magic at all, it's just leveraging the language.

Myles
Agreed. This has nothing bad about it.
Jani Hartikainen
I've looked at it this way too, but IMHO, it just doesn't "feel right" when I do this... Then again, I tend to look at things like I'm writing C# or Java classes...
Austin Hyde
Think of how you'd do it C# or Java way. That would quite likely work with PHP as well. However, I think you will find that approach will be much more complicated than this one.
Jani Hartikainen
A: 

For most of the things I've worked on, the MVC framework seems too bloated.

I prefer to use a templating engine, like smarty (www.smarty.net)

You still get the same separation of code and presentation. I find it's creates neater organization of code, where you're managing all the files and directory structure. Code can be grouped logically, rather than by pages.

Tom Kiley
you cant compare smarty with mvc frameworks.
Galen
I agree. I was just trying to offer an alternative that he could look at.
Tom Kiley
It's not really that I feel they are too bloated. I am simply trying to find a way to not use what I call "magic", meaning dynamic conversion between strings and types and methods. Smarty is a great alternative to a full-blown framework, though.
Austin Hyde
A: 

Sounds like you're problem is with ORM magic not the MVC which is just a muggle.

4.669201
Well, not really... It's about the conversion from a query/route/uri/whatever to a controller class. What I meant about the CMS and DB is that the app has to "know" what table to look in and from there. Consider a `Pages` table with a record `Title: News, Slug: news Type: Blog` and in the app, a `class Blog extends Page { public $title; public $articles; }` How would the application interpret a request to `/news/article/3` without magic telling it what class to create?
Austin Hyde
+1  A: 

I don't know which frameworks you did look at. The ones I used so far (CodeIgniter and Yii) do work magic, but have safeguards. For example, all controllers need to be extended from Controller class, so you cannot instantiate any class, only a controller. With CodeIgniter, it is recommended that all controller methods that should not be accessible via browser are declared private. Yii brings this to another level, requiring that all such methods start name with "action" (it would be "actionEdit" in your example), so you really cannot call some arbitrary method from outside.

I find all this magic to be very useful when there are multiple developers on a team, because it makes sure people follow the rules and it's much easier to get into each other's code and understand what happens. Without such conventions being enforced, you have to spend time in the browser tracking which link leads where and then digging into PHP code to find where it goes. It can turn into a big mess with so loose language like PHP (no strict types, variables declared on first use, dynamic arrays, etc.) In C# or Java it's the language that enforces order, in PHP it's the job for frameworks.

Milan Babuškov
+2  A: 

There are, in fact, two questions here.

  1. Is PHP as a language used properly here.
  2. Is the logic of this code too "magical"

I can give my view on it as a PHP developer and software engineer involved in development of web applications mostly based on some MVC framework

1) Every language comes with its own syntax that provides more or less expressiveness. I agree that all the power of one language should not be used on every line of code for the sake of readability and simplicity. But in this case, where core of the MVC is designed and implemented I see no reason not to use them especially on the places where end user (application developer in this sense) doesn't see this magic if it is well encapsulated. I presume this is a simplified and stripped off snippet you posted since there should be some other considerations regarding its design, but creating new instance based on a string name, and calling a function the same way is regular approach in PHP world.

2) I agree that this code is logic wise somewhat magical, especially because it probably provides the promise of generality to the developer. There are different approaches regarding this, that in most times reduce generality of the solution and provide some means of direct definition of the mapping through command map or similar approach (DB for example as you said). This way magic is under the hands of the developer. This, in general, is not suitable for rapid development since there is a lot of manual work in setting the mappings that are by router magic in your case automagically resolved.

Hope it helps a bit.

Cheers, Ivan

ivanjovanovic
A: 

I don't believe that you should be able to dynamically create classes based off of a string, then call methods on it specified as strings.

That's seems like an arbitrary thing that we "shouldn't" be able to do?

The magic you're talking about is just abstraction. You (hopefully!) use all kinds of abstraction in your day-to-day work already.

So what about this particular abstraction do you objectionable?

I really think the best answer to this question is: Get over it and get back to work! :-)

timdev