PHP, how I hate thee

krogen

[H]ard|Gawd
Joined
Jul 22, 2009
Messages
1,076
Two days ago I was overjoyed when I was told I can use a framework of my choice on my next project. My workplace tool is a proprietary CMS / framework spaghetti-code behemoth. It gets the worst of all worlds. It's slow, as it uses XSL transformations for its views. Working with DOM is a pain-in-a-butt in PHP, so you end up with a view that does a lot more work than the actual controller. It has a very weak concept of route handling, as it primarily uses pre-defined routing structure. Writing something like a basic REST API is quite hard, as you have to skip the regular routing mechanism and use a different one. There are three distinct ways that a route can be handled. Configuration is a non-data driven mess split across many different files. And on, and on, and on...

Yeah, so my regular workplace tool kinda stinks. As I said, I was happy to learn that I could pick any framework on my next project, only to find out that the grass isn't too much greener on the other side.

I haven't worked with any other PHP frameworks, so I picked the most popular 7 for a review. I have some experience beyond PHP web development (Ruby + Sinatra, Node.js + Express, Clojure + Compojure). I know what makes these latter tools great.

Here's a basic task that I gave myself for each framework:
Output "hello {bar}" content to the browser on a "/hello/{bar}" GET request, with a content type of "text/plain" and a status code of 200. Should be easy enough, I figured.

Every framework that I looked at gave me at least two ways to define a controller. For example, Laravel docs told me this:
Code:
Route::get('foo/{bar}', function($bar) {
  return (new Response("hello $bar",200))->header('Content-Type','text/plain')
});
// Or, alternatively
Route::get('foo/{bar}', 'FooController@show');
class FooController extends Controller {
  public function show($bar) {
    return (new Response("hello $bar",200))->header('Content-Type','text/plain')
  }
}

Now, why do we need two ways to define a controller? Two is better than one? Not in programming. Why can we not have one concise way? I like the former way a whole lot more, and yet Laravel favors the latter for the following reason:

Instead of defining all of your request handling logic in a single routes.php file, you may wish to organize this behavior using Controller classes.

Huh? Why can't we just define a namespace and a function within, the controller? Why the boner for OOP? Clearly the routing itself doesn't follow clean OOP practices, as it uses a static method.

Furthermore, it's great to see that in 2015 we have to define a magical string to refer to a method:

Code:
'FooController@show'

Would this not be so much nicer?

Code:
Route::get('foo/{bar}',\Foo\show);

Oh, wait, not only the syntax is absolutely bonkers with namespaces, I don't think this namespaced function reference would even work, so perhaps we have to use magical strings, after all.

Last but not least - perhaps this one is more framework related, but I've seen no frameworks that try to attempt this - why not define multiple closures, a la Express.js? Are closures so new to the language PHP developers haven't figured out how to take advantage of them?

Code:
Route::get('foo/{bar}',function($bar) {
  // validate if $bar is okay here, if not, return an error response
},function($bar) {
  // $bar is okay, so we can proceed
});

Such a simple way of splitting logic, yet it doesn't seem to be supported across any popular frameworks.

Beyond Laravel, the framework hilarity ensues. For example, here's a way to define that same hello world route in Symfony:

Code:
class HelloController {
  /**
   * @Route("/foo/{bar}", name="hello")
   */
  public function indexAction($bar) {
    $response =  new Response("hello $bar", Response::HTTP_OK);
    $response->headers->set('Content-Type', 'text/plain');
    return $response;
  }
}

Note the annotation... I guess Symfony devs gave up on magical strings referencing some method, so they define magical annotations instead.

Sort of like function metadata, maybe we'll see a half-baked implementation of that in 2020 with some crazy backwards-compatible syntax.

Anyways, back to the project that I was so happy about. Here's the scenario:

Build a calendar with some basic functionality that gets it's data from a remote source.

Calendar. Easy, built those before. How about that remote source part? Maybe we could use some exciting middleware for that? Yes, sounds like a great idea!

Let's pseudo code this:
Code:
// middleware
if {project-root}/data/calendar.xml does not exist
invoke get_data
else if {project-root}/data/calendar.xml is old
invoke get_data
else
// calendar data is not old and it exists, so we can proceed with request

In the first case, the action has to be synchronous because we need this data prior to rendering the calendar. In the second case, we could do the task asynchronously because we already have the data, we only need to refresh it. In the last case we don't need to do anything.

The second case... Ooops, can't do that! PHP has no concept of performing things asynchronously. Threads could be used on Linux (Unix?) systems with pthreads, but those are still new, unproven, and the extension is not found on majority of systems.

So, for the lulz, I need to either build a system-level job that will get this data, or suck it up and perform the task synchronously when it needs to. Except the latter is unacceptable as the file if large.

So, what's the purpose of framework middleware when I can't even get the simplest things done?

End rant.

tldr:
I'm angry about PHP & PHP frameworks
 
This would be pretty trivial (if I'm understanding correctly) using promises in AngularJS. If you're not married to PHP, that may be a better option, especially since you're already familiar with Node.js and Express (MEAN stack FTW).
 
tldr:
I'm angry about PHP & PHP frameworks

Welcome to, errr..... Every time I have to look at or touch anything PHP related?

This would be pretty trivial (if I'm understanding correctly) using promises in AngularJS. If you're not married to PHP, that may be a better option, especially since you're already familiar with Node.js and Express (MEAN stack FTW).

Yeah, just use the server that PHP is running on to statically serve an Angular SPA. It's the most useful thing a PHP server could possibly do. Besides, unless this application is very mean-time-to-content-in-DOM sensitive (like Twitter or something), you're probably better off with the client-side rendered application anyways.
 
Back
Top