PHP vs. RUBY: What’s the Point?

Tweet

You will no doubt have read one of the many articles out there comparing the merits of PHP against Ruby, or more commonly to my exasperation, PHP vs Rails. I hope, like me, you find such articles pointless exercises and nothing short of language trolling. It’s just not a level playing field.

Somehow developing for the web brings these two different beasts together for comparison. PHP a.k.a Personal Home Page Tools (thanks wikipedia) is a language/framework developed specifically for the web. Ruby on the other hand is a general purpose language conceived by one man Matz, in a quest to create a utopian programming language.

Starting out in PHP, you will probably create a few pages with code laced in the HTML. Then after realising how painful that can be to maintain, you will start abstracting your business logic and presentation layers using something like Smarty. You will get a bit more object orientated and no doubt grab something like Zend Framework or CodeIgniter to develop your own applications. Hopefully, that all sounds familiar.

When it comes to Ruby, so many developers ignore such a sensible path of development. I know I certainly did. Where do most people start with Ruby, myself included? Rails, of course. We watch the “build a blog” video and, presto, we are all sold. I would never discourage anyone from picking up Rails and running with it, but it’s not Ruby for beginners. When you use Rails, a lot of great developers have spent a lot of time abstracting all the horrible nitty gritty stuff away. Migrations just work, Routing just works, logging and testing and right there for you to use. Rails is a framework that gets out the way and lets you focus on the problem you want to solve.

Hello Rack

One good reason to start with Rails is, when it comes to developing for the web, Ruby on its own is nothing short of intrusive. Sure we can use the standard library CGI class, upload the file to the server, make it executable and we are done. Compare that with a PHP script.

Even DHH blogged about the immediacy of PHP. Your gratification is instant. Want to test a quick bug fix? Just hit refresh on the browser. None of this restarting mongrel, Passenger, or whatever is required.

So how can we get to that kind of instant Ruby web apps without resorting to rails s. Well, how about we use the framework Rails itself uses? Rack.

Rack is the interface between Rails apps and the HTTP protocol. It is also the basis of pretty much all Ruby web frameworks, Sinatra & merb included.

Rack incorporates all that low level code that framework developers were duplicating across projects. It basically scoops up any web server available and uses it to serve your apps (by web server we are talking mongrel, WEBrick, thin and so on).

To get started with Rack it’s simply a case of installing the gem, creating a rackup file (*.ru), and starting the app.

The hello world of Rack looks like the following (hello.ru):

class HelloWorld
  def call(env)
    [200, {"Content-Type" => "text/html"}, ["<h1>Hello world!</h1>"]]
  end
end

run HelloWorld.new

Then in the console, rackup hello.ru. You will see a bit of server output with the port the server has started on (usually 9292). Just navigate to http://localhost:9292 and see the glory.

To dissect this simple application (and it is an application), basically we have a method named call that receives the environment and returns an array of three things, status, headers and body. By environment we are not talking staging, production etc. instead it’s the more CGI set of variables we see in PHP’s $_SERVER super global, REQUEST_METHOD etc.

The status codes are pretty self explanatory and the contents of the headers hash will also be familiar. The body we see in the hello world example is an array, or more specifically, it must respond to each. Finally, at the end of the file we see the run method spinning up an instance of our hello world application.

So the basic rules of a Rack application are it must have a method call that accepts the environment hash and returns status, headers and body, and body must respond to each.

Echo ‘Hello World’

We have seen a basic Rack application, but how does that compare to the simplicity of:

<? php
echo "<h1>Hello World</h1>";
?>

At face value, it certainly seems more convoluted, so let’s look at what Rack gives you to make it more attractive.

The Builder

When it comes to hello world PHP is pretty hard to beat. Luckily for the Rubyist in us, hello world applications are in low demand, and Rack comes with a whole lot more than wrapping servers. Rack itself ships with many micro Rack applications that will assist us in building our frameworks. They include all the helpful stuff like logging, sessions, url mapping and so on.

One of the absolute gems of Rack has to be Rack::Builder. This is a Domain Specific Language (DSL) that allows to construct and mash together Rack applications easily. Consider building a PHP application that has a public page and a secret page. In PHP we could create two files that perform these duties. An alternative would be to create a .htaccess file that directs all incoming requests to a single file like so.

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ /index.php?page=$1 [L]
<?php
if ($_SERVER['REQUEST_URI'] == '/secret') {
  echo "Shhhh";
} else {
  echo "This is public";
}
?>

Not too bad, its implementation using Rack::Builder could look something like:

app = Rack::Builder.new do
  map "/" do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["This is public"]] }
  end

  map "/secret" do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Shhhh"]] }
  end
end

run app

Pretty neat? What we have done here is implement Builder to map urls to given actions. These actions are just Proc just now as we find our feet, they return the golden trio we seen in our hello world app.

This is infinitely scalable as well. For example, let’s look at a path such as ‘/secret/files’. Our PHP version gets hairy enough to warrant a rethink (we dont want to go down the line of adding files to relative directories do we?), in Rack we simply nest some map blocks.

map "/secret" do
  map "/" do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Shhhhh"]] }
  end

  map "/files" do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Here be dragons"]] }
  end
end

Hopefully, you are nearly sold on Rack. While we are still feeling the love, let’s spice it up a bit by adding some more kinky Rack toys.

Rack = Damn Sexy

We mentioned before that Rack is more that a server interface. It comes with a wealth of “components” which are themselves Rack applications. Now, we will look at how we can implement a couple of these.

I always find logging helpful when developing applications.

require 'logger'

  app = Rack::Builder.new do
  use Rack::CommonLogger
  Logger.new('my_rack.log')

  map "/" do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["This is public"]] }
  end

  map "/secret" do
    map "/" do
      run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Shhhhh"]] }
    end

  map "/files" do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Here be dragons"]] }
  end
end

run app

We have been talking about secret areas and dragons, so we better lock all that up. HTTP Basic Authentication is always good for securing things.

require 'logger'

  app = Rack::Builder.new do
  use Rack::CommonLogger
  Logger.new('my_rack.log')

  map "/" do
    run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["This is public"]] }
  end

  map "/secret" do
    use Rack::Auth::Basic do |user, password|
      user == 'super_user' && password == 'secret'
    end

    map "/" do
      run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Shhhhh"]] }
    end

    map "/files" do
      run Proc.new {|env| [200, {"Content-Type" => "text/html"}, ["Here be dragons"]] }
    end

  end
end

run app

That was incredibly easy, I remember the days of setting up .htpasswd files and so on.

Rackup

I started this article as if it were a PHP vs Ruby nonsense. And throughout the article I have made references about how we could do this in PHP and compared it to Rack. It was all a cunning rouse, preying on the language troll in all of us. Fact is, both have merits and even comparing Rack with PHP is hardly fair.

I hope this has given you a taste of how flexible, maintainable, and joy-inspiring using Rack is. It’s a great place to start when learning Ruby because there is enough ‘magic’ to keep our interest, but not enough to obscure learning.

We have not finished there though. You will remember all the big frameworks are built on top of Rack. We can actually implement mystical middlewares using Rack that intercept the normal flow of our applications and temporarily hand control to Rack applications. Could be scary, but Rails loves it.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://nicklasos.heroku.com Nick

    Nice, I like it.

  • Gazler

    While hardly a comparison between PHP and Ruby and more of a beginners Rack tutorial, this is a good read. A minor correction. PHP as of version 3 stands for “PHP: Hypertext Preprocessor.” http://en.wikipedia.org/wiki/PHP#History

    • Brian

      PHP: Hypertext Preprocessor. I have been using PHP for about 10 years, and Ruby for about 3. This isn’t really a php vs ruby comparison, it’s really PHP vs Rails–which is sort of like apples to oranges. However, you are right in that most people don’t approach ruby shy of a framework for web development.

      Unfortunately, that hasn’t always been something readily available in PHP, but those frameworks are just as available to learn PHP side by side with a framework.

      There is a gross misunderstanding of PHP by way means of practice. It is not always gunslingers with MySQL and echo’s in the HTML. However, it has been demonstrated this way for a long time, which is not really a fair gauge of practicality. You could probably write Ruby just as poorly. When people think Ruby they immediately think Rails. When people think of PHP they don’t immediately think of PHP 5’s OO improvements or Lithium or Cake.

  • Randy

    Ok, fellow language troll, compare it to Python and Django and see if you still feel the same.

    Ruby is NOT maintainable, doesn’t scale well, and leads to badly written unreadable code. I mean, seriously,

    run Proc.new {|env| [200, {“Content-Type” => “text/html”}, ["Shhhhh"]] }

    ??? Maintainable = False;

    But, you already know that :)

    Anyway, cheers for the writeup and honesty about your intentions. Good work.

  • http://rtdptech.com rtdp

    Nice Article !!

    This article makes a very good point about – ” Your gratification is instant. ”

    Many of my friends started web development with *something and then start with rails and then they say that *something is better because you start early, it’s easy and so, so… but point is it’s instant gratification – which won’t scale..

    Rails is basically convention over configuration, and so one starts loving rails, when he understands those conventions is what I feel after using rails since last 2 years.

  • http://josemota.net José Mota

    You just made me realize I’ve been using Rack all wrong on a project I’m building, thanks for pointing this out.

    The point of this post is really good for laying some common ground between the two languages. Well done, Dave.

  • troll

    @Randy

    `Maintainable = False;`
    returns true, so does that mean that you’re trying to say that it IS maintainable?

    It sounds stupid to point that out, but pointing out an obscure piece of code in Ruby is too. One could do the same with Python.

    [p[:i]+[l[0]]+p[i:] for i in range(sz) for p in perm(l[1:])]

    Here you go, python is too complicated because I don’t understand it. It’s not maintanable! It doesn’t scall! I’m a troll from 2005!

    Best <3

  • http://www.tedroche.com Ted Roche

    “praying on the language troll in all of us.”

    No false idols here, should be:

    preying on the language troll in all of us.

    Language articles always bring out the trolls. Perl./Python/PHP/Ruby can all do this basic http manipulation, and each can build fairly complex object-oriented (-ish) processes. It’s a poor craftsman who blames his tools, or only uses a single one. Everyone should try several languages and work with the ones that speak best to them.

    • http://bangline.co.uk Dave Kennedy

      Passed teh spell checker lolz. Thanks for pointing it out, updated the article. And could not agree with your comments more about best tool for the job, out a decent tool box!

  • Bryce

    Here via Sitepoint tech times

    You mention the merit of abstraction in PHP – by the use of templating and frameworks. But then you show these Rack examples that, to me, seem to throw that thinking out and mix everything back together again – like beginner PHP.

    Granted I don’t know that much about Ruby, Rack or Rails – but to me those examples seem to have more in common with what setting up routes in a PHP framework is like than with the PHP ‘equivalents’ you show.

    I know they’re examples, but would you seriously build an app on code like that?

  • http://www.solidwebcode.com Rein

    If we’re talking about rack and rails, why not compare it to Symfony or CodeIgniter? I use Symfony a lot and there’s routing, debugging, MVC and abstraction in it – all like Rails, but then in PHP.

    I’ve tried Rails (Ruby) and Django (Python), but in the end most of my customers have simple hosting with only apache/php and it stays my language of choice. I’ve chosen Symfony 2 for now, but there’s probably 100ths of frameworks out there that each have their own vices and virtues. And whatever you say, that isn’t true for Ruby or Django.

  • Machiel

    A minor correction:

    It’s PHP: Hypertext Preprocessor, not Personal Home Page Tools.

  • http://emokemi.com Stefan Froelich

    I almost stopped when i read ‘Personal Homepage Tools’. The dang thing is “Hypertext Preprocessor”.

    Maybe we read different versions of wikipedia, but what i read there is

    “While PHP originally stood for “Personal Home Page”, it is now said to stand for “PHP: Hypertext Preprocessor”, a recursive acronym.[8]” http://en.wikipedia.org/wiki/PHP

    This is the first disappointing article I have read on any sitepoint site.

    Why would I bother with all this when apache can do it for me??? Simply route to all the pages i want. If I want realm auth,

    <?php
    if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="My Realm"');
    header('HTTP/1.0 401 Unauthorized');
    echo 'Text to send if user hits Cancel button';
    exit;
    } else {
    echo "Hello {$_SERVER['PHP_AUTH_USER']}.”;
    echo “You entered {$_SERVER['PHP_AUTH_PW']} as your password.”;
    }

    No use doing all that you did. I think you actually spoilt rack for me because, as you said, Instant gratification is what drives us.

    • http://emokemi.com Stefan Froelich

      What I find wrong about all this is, muddling in the routing. You are just doing what the server should do.

      It isn’t a rack thing, but a problem with frameworks even in php. You can perform magic with .htaccess and a little ReGex knowledge.
      Just my 2 cents.

    • http://bangline.co.uk Dave Kennedy

      You probably should have stopped reading and started again, I feel you missed the point of the article somewhat. A lot of people seem to take the term Personal Home Page tools as derogatory, Im a PHP guy also and happy in the fact that Im using a language aimed directly at the web. If it makes you feel less a developer Im sorry for mentioning PHPs history (even if in error)

      Rack here (it’s a heck of a lot more) is a tool for us to get quick feedback on web based Ruby apps. Save us from getting lots abstracted away in larger frameworks and focus on what we want to do.

  • http://webdev.dluces.com Diego Luces

    I see you don’t compare PHP to Ruby itself as Ruby itself is not intended for the web, but it may be when using Rack. But then again, you’re comparing a framework with a language, like most of the articles out there.

    Instead of comparing PHP to Ruby on Rails or Rack, it’d be more accurate to compare PHP “on Symfony” (or any other framework) to Ruby on Rails. With that in mind, I think that each language have some features to envy from the other. Not quite sure if I can say that one is “better” than the other, though.

    Personally, I choose PHP on Symfony2 over Ruby on Rails. Works better for me, but then again, that’s a matter of choice (considering your clients’ needs, your team, etc.)

    • http://bangline.co.uk Dave Kennedy

      Strictly speaking PHP is a framework, but I hope you noticed not once did I say one is better than the other, I may have shown approaches, but never compared them or merits or otherwise.

      The gist is (and I see you think the same way) it is comparing apples and oranges

      • http://definitivecode.com Robert Rouse

        Not sure why you’d say PHP is a framework. It is no more of a framework than Ruby is.

        PHP is a language with a standard library. It just so happens that it is geared toward the web, but can also be used for command line purposes.

        Likewise, Ruby is a language with a standard library. It isn’t geared specifically for the web, but can be used as such.

        • http://bangline.co.uk Dave Kennedy

          @Robert Rouse I say it only because PHP being what it is, vanilla installation abstracts so much of the nitty gritty. As a PHP dev, pre Zend and CodeIgnighter I build my own framework which wrapped/routed/whatever the common lower level stuff… only it wasnt that low level as it was PHP after all.

          But before this goes out of context again, the previous reply was a bit flippant as at no point did the article get into which is better, PHP vs Ruby, Rails vs Symphony. That kind of thing is pointless, we all know better and use the best tool for the job.

          Finally, PHP is great, I have converted somewhat though and feel more at home using Ruby for some applications. However I have no intention in the near or distant future of dropping PHP from my toolkit, its far too useful. Well untill the next big thing comes along then Ill write an article comparing that to PHP :)

  • BT

    First of all, I want to say thanks for providing example code that actually works. Other tutorials simply failed to work or failed to give minimal example code (some give subminimal example code that leaves parts out).

    You mentioned rack might be able to give you instant gratification on the level of php, but you don’t really get to how. After I rackup my ru file, modifying the file seems to do nothing until i re-rackup. Just wondering if there’s a config switch or something.

  • http://www.9jamkt.com Ekene

    Php is always better than rails for the web whether you like it or Not. Just make sure not to compare the number of jobs accomplished with both… Cos you’ll be disappointed for writing this. But nice you spoke your mind.

  • JohnG

    You lost me completely when you threw credibility out the window by quoting yet another piece of Wikipedia mis-information. As for the rest you said about PHP, you simply couldn’t be any more wrong. I can’t speak to the Ruby content because I don’t use, nor see the need or desire for, Ruby.

    • marcc

      @JohnG: Talk about credibility (“I can’t speak to the Ruby content because I don’t use, nor see the need or desire for, Ruby”). Such open-mindedness! And I’m not even trying to defend the author, he’s Scottish, for gawd’s sake! Dave, just kidding, I love Jacobites (and Ruby/RubyOnRails – two very different things, btw, but I digress).

  • Alan

    Nice intro article re Rack. Is there a simple description, source code, and example of what each Rack middleware component does?
    Taking Rack::CommonLogger as an example, I assume you have to actually log activities to the Logfile. All your example did was to create the Logfile? But where would I find such detail?
    Regards
    Alan