PHP
Article
By Phil Sturgeon

PHP vs Ruby – Let’s All Just Get Along

By Phil Sturgeon

Quite often you see developers who have a lot of experience in one language try to play with another, then make a rather quick comparison between the two. This comparison is usually quite worthless, but the clickbait titles get them a lot of traffic.

Instead of doing that, I thought it would be interesting to have a slightly more fair comparison, from the perspective of someone who really enjoys writing both PHP and Ruby, and has done so for years. The aim here is not to find out which is “better”, but to point out a few key things I like about Ruby and its ecosystem.

Screenshot 2015-11-21 01.20.42

Conceptual differences

Different languages are often compared to find out which is better, when the differences that make them up are more ideological. Sometimes one thing seems better to one group of people, when that very same thing makes the language a nightmare for other developers.

With this in mind, before I get into the “bits of Ruby I like in comparison” I think explaining a few of these conceptual differences will be important.

Method, Variable, Property?

PHP offers different syntax to access properties, methods or variables. Ruby does not.

PHP

$this->turtle   # Instance Property
$this->bike()   # Method
$apple          # Variable

Ruby

@turtle         # Instance Property
turtle          # "Instance Property" using attr_reader: :turtle
bike            # Method
apple           # Variable

Pedants will point out here that attr_reader :turtle will define a method dynamically, which is used as a getter for @turtle, making turtle and bike the same thing. A PHP developer looking at usage of turtle with no method or variable name explicitly defined will be incredibly confused about where it’s coming from.

This should not be something that causes you problems too often, but it has caught me out now and then. Sometimes folks on your team might change things from an attr_reader to a full method, or vice-versa, and it might cause knock-on affects.

That said, it can allow for some really flexible APIs, and let you do some cheeky things that you’re thankful for in the heat of the moment.

Deleted a field, but have loads of code, and a JSON contract still expecting it to be there?

class Trip
  def canceled_at
    nil
  end
end

That’ll work nicely. Anything calling trip.canceled_at is going to get a nil for this field, which is fine. We’ll remove it properly later.

Type Hints vs. Duck Typing

In the PHP world, type hints are a weird and wonderful thing. Languages like Golang absolutely require you to define a type for arguments, and return types. PHP added optional type hinting in 5.0 for arguments. You could require arrays, specific class names, interfaces or abstracts, and more recently callables.

PHP 7.0 finally allows return type hinting, along with support for hinting int, string, float, etc. This was done with the scalar type hints RFC. This RFC was bitterly argued and debated, but it got in there, and it is still completely optional; good news for the varied user-base that is PHP.

Ruby has literally none of that.

Duck Typing is the way to go here, which some folks in the PHP world also maintain is a superior approach.

Instead of saying: “The argument needs to be an instance of a class which implements FooInterface” and knowing that FooInterface will have a bar(int $a, array $b) method, you essentially say: “The argument can be literally anything that responds to a bar method, and if it doesn’t we can do something else.”

Ruby

def read_data(source)
  return source.read if source.respond_to?(:read)
  return File.read(source.to_str) if source.respond_to?(:to_str)
  raise ArgumentError
end

filename = "foo.txt"
read_data(filename) #=> reads the contents of foo.txt by calling 
                    #   File.read()

input = File.open("foo.txt")
read_data(input) #=> reads the contents of foo.txt via 
                 #   the passed in file handle

This is really flexible, but to some this is a code smell. Especially in a language like PHP where a int(0) or int(1) are considered valid boolean items in weak mode, taking any value and just hoping it works right can be a scary move.

In the PHP world, we might just define two different methods/functions:

function read_from_filename(string $filename)
{
    $file = new SplFileObject($filename, "r");
    return read_from_object($file);
}

function read_from_object(SplFileObject $file)
{
  return $file->fread($file->getSize());
}

$filename = "foo.txt";
read_from_filename($filename);

$file = new SplFileObject($filename, "r");
read_from_object($file);

That said, if we wanted to do the exact same duck typing approach in PHP, we easily could:

function read_data($source)
{
    if (method_exists($source, 'read')) {
        return $source->read();
    } elseif (is_string($source)) {
        $file = new SplFileObject($source, "r"));
        return $file->fread($file->getSize());
    }
    throw new InvalidArgumentException;
}

$filename = "foo.txt";
read_data($filename); #=> reads the contents of foo.txt by calling 
                      #   SplFileObject->read();

$input = new SplFileObject("foo.txt", "r");
read_data($input); #=> reads the contents of foo.txt via 
                   #   the passed in file handle

You can do either in PHP. PHP doesn’t care.

Pretending that Ruby is “better” because it uses duck typing would be misguided, but very common. You may prefer the approach, and PHP can do both, but basically, Ruby is lacking a feature that PHP has. Being able to do whichever you please does strike me as a bit of a win for PHP, when it is completely impossible to type hint in Ruby even if a developer wanted to.

That said, there are many PHP developers who are strongly against type hints, who wished there were none at all and were upset when more were added in PHP 7.0.

Interestingly, Python used to be totally lacking type hints just like Ruby. Then recently they added them. I’d be interested in knowing how many people flipped a table over that transition.

--ADVERTISEMENT--

Fun Features

Once I’d accepted those differences, I was able to focus on the fun stuff. These are the features I started to notice myself using regularly, or least fairly often.

Nested Classes

Nested classes sound a little alien to PHP developers. Our classes live in namespaces, and a class and a namespace can share the same name. So, if we have a class that is only relevant to one class, we namespace it and that’s it.

So, we have a class called Box, which can throw a ExplodingBoxException:

namespace Acme\Foo;

class Box
{
    public function somethingBad()
    {
      throw new Box\ExplodingBoxException;
    }
}

That exception class declaration has to live somewhere. We could put it at the top of the class, but then we have two classes in one file and… well that feels a little funny to many. It also violates PSR-1, which states:

This means each class is in a file by itself, and is in a namespace of at least one level: a top-level vendor name.

So, it goes in its own file:

namespace Acme\Foo\Box;

class ExplodingBoxException {}

To load that exception we have to hit the autoloader and go to the filesystem again. Doing that isn’t free! PHP 5.6 lowers the overhead for subsequent requests if the opcode cache is enabled, but it is still extra work.

In Ruby, you can nest a class inside another class:

module Acme
  module Foo
    class Box
      class ExplodingBoxError < StandardError; end

      def something_bad!
        raise ExplodingBoxError
      end
    end
  end
end

This is available to the defining class, and available outside of the class too:

begin
  box = Acme::Foo::Box.new
  box.something_bad!
rescue Acme::Foo::Box::ExplodingBoxError
  # ...
end

That might look a little weird, but it’s pretty cool. A class is only relevant to one class? Group them!

Another example would be database migrations.

Migrations are available in many popular PHP frameworks, from CodeIgniter to Laravel. Anyone who has used them often will know, if you reference a model or any other class in your migrations, then later you change that class, your old migrations will break in weird and wonderful ways.

Ruby gets around this nicely with nested classes:

class PopulateEmployerWithUserAccountName < ActiveRecord::Migration
  class User < ActiveRecord::Base
    belongs_to :account
  end

  class Account < ActiveRecord::Base
    has_many :users
  end

  def up
    Account.find_each do |account|
      account.users.update_all(employer: account.name)
    end
  end

  def down
    # Update all users whose have account id to previous state
    # no employer set
    User.where.not(account_id: nil).update_all(employer: nil)
  end
end

The nested version of the User and Account ORM models will be used instead of the global declared classes, meaning that they are more like snapshots in time of what we need them to be. This is far more useful than calling code with moving goalposts, which could change at any point.

Again, this will sound mad to some people, until you’ve been bitten a few times.

PHP developers often end up copying complex logic to do this, or write the SQL by hand, which is a waste of time and effort compared to just copying the relevant bits of a model over.

Debugger

XDebug is a wonderful piece of work. Don’t get me wrong, using breakpoints is amazing, and revolutionizes the way PHP developers debug their applications, moving beyond the “var_dump() + refresh” debug workflow that is wildly common amongst junior developers.

That said, getting XDebug to work with your IDE of choice, finding the right addon if it’s missing, getting the php.ini tweaked for the right version of PHP to enable zend_extension=xdebug.so for your CLI and web version, getting the breakpoints sent out even if you’re using Vagrant, etc., can be a massive pain in the backside.

Ruby has a bit of a different approach. Much like debugging JavaScript in the browser, you can just bang the debugger keyword into your code and you’ve got a breakpoint. At the point your code executes that line – be it the $ rails server, a unit test, integration test, etc., you’ll have an instance of a REPL to interact with your code.

There are a few debuggers around. One popular debugger is called pry, but another is byebug. They’re both gems, installable via Bundler by adding this to your Gemfile:

group :development, :test do
  gem "byebug"
end

This is the equivalent of a dev Composer dependency, and once installed you can just call debugger if you’re using Rails. If not, you’ll need to require "byebug" first.

A handy Rails guide Debugging Rails Applications, shows how things look if you shove the keyword in your application:

[1, 10] in /PathTo/project/app/controllers/articles_controller.rb
    3:
    4:   # GET /articles
    5:   # GET /articles.json
    6:   def index
    7:     byebug
=>  8:     @articles = Article.find_recent
    9:
   10:     respond_to do |format|
   11:       format.html # index.html.erb
   12:       format.json { render json: @articles }
 
(byebug)

The arrow shows the line the REPL instance is running in, and you can execute code from right there. At this point, @articles is not yet defined, but you can call Article.find_recent to see what is going on. If it errors, you can either type next to go onto the next line in the same context, or step to go into next instruction to be executed.

Handy stuff, especially when you’re trying to work out why the heck some code is not giving you the output you expect. Inspect every single value until you find the culprit, try and make it work in that context, then whatever ends up being the working code can be copied and pasted into the file.

Doing this in your tests is amazing.

Unless

A lot of people do not like unless. It is oft abused, like many features of many programming languages, and unless has been winding people up for years as this article from 2008 points out.

The unless control structure is the opposite of if. Instead of executing the code block when a condition evaluates to true, it will only evaluate when the condition evaluates to false.

unless foo?
  # bar that thing
end

# Or

def something
  return false unless foo?
  # bar that thing
end

It makes things a bit easier to work out, especially when there are multiple conditions, maybe an || and some parentheses. Instead of switching it with a bang like so: if ! (foo || bar) && baz you can simply do unless (foo || bar) && baz.

Now, this can get a bit much, and nobody at work would let you submit an unless with an else on it, but an unless by itself is a handy feature.

When people requested this feature for PHP in 2007, it was ignored for a while until PHP creator Rasmus Lerdorf said it would be a BC break to anyone with a unless() function, and it would be “not obvious to non-native English speaking people like myself.”

It is an odd word that essentially means not-if even though it logically should be equivalent to “more” as in the opposite of “more” would be “less” and sticking “un” in front of it suddenly completely changes the meaning entirely.

I disagreed with that, and still do. People reading unless are not going to think it is the “opposite of less” just based on the un. If that were the case, people would read the function uniqid() and think it was the opposite of iqid().

We suggested as much, and got told that we were “just being silly.” It has since been labeled wontfix.

Predicate Methods

There are a few cool conventions in the world of Ruby that PHP is forced to solve in other ways. One of these is predicate methods, which are methods with a boolean response type. Seeing as Ruby has no return type hints, this is a good suggestion of intent to developers using the method.

Ruby has many built in, such as object.nil?. This is basically $object === nil in PHP. An include? instead of include is also a lot more clear in that it is asking a question, not executing an action.

Defining your own is pretty cool:

class Rider
  def driver?
    !potential_driver.nil? && vehicle.present?
  end
end

Many PHP developers will do this by prefixing the method name with is and/or has, so instead you have isDriver() and maybe hasVehicle(), but sometimes you have to use other prefixes. A method I wrote in Ruby which was can_drive? would be canDrive() in PHP, and that is not clear it is a predicate method. I’d have to rename it isAbleToDrive() or some guff to make it clear with the is/has tradition rolling in the PHP world.

Even Shorter Array Syntax

In PHP, defining literal arrays is easy, and has been made much less verbose in PHP 5.4 with the addition of short array syntax:

// < 5.4
$a = array('one' => 1, 'two' => 2, 'three' => 'three');
// >= 5.4
$a = ['one' => 1, 'two' => 2, 'three' => 'three'];

Some would say that is still a little too verbose. In Ruby 1.9 they added a new option, to allow rockets to be replaced with semi-colons, which if done in PHP would cut this syntax down a little further:

$a = ['one': 1, 'two': 2, 'three': 'three'];

That is rather nice if you ask me, and when you get to nesting arrays it really saves a bit of typing when you’re doing it a few hundred times in a day.

Sean Coates suggested this with an RFC back in 2011, but it never made it in.

This may well not make it into PHP ever. PHP tries to be minimalist with its syntax, and is very often against adding new approaches to do old things, even if the new approach is quite a bit nicer. Basically, syntactic sugar is not a priority for PHP maintainers, whereas it seems to be almost a core goal of Ruby.

Object Literals

The same RFC linked above highlights a feature in Ruby that I would love to see put into PHP: object literals. In PHP, if you would like to define an StdClass with values, you have two approaches:

$esQuery = new stdClass;
$esQuery->query = new stdClass;
$esQuery->query->term = new stdClass;
$esQuery->query->term->name = 'beer';
$esQuery->size = 1;
 
// OR

$esQuery = (object) array(
   "query" => (object) array(
       "term" => (object) array(
           "name" => "beer"
       )
   ),
   "size" => 1
);

I know this is how it’s been done in PHP forever, but it could be so much easier.

The proposed syntax in the RFC matches Ruby almost exactly:

PHP

$esQuery = {
   "query" : {
       "term" : {
           "name" : "beer"
       }
   },
   "size" : 1
};

Ruby

esQuery = {
   "query" : {
       "term" : {
           "name" : "beer"
       }
   },
   "size" : 1
}

I would really really like this to be done, but again, it has been attempted in the past and met with little interest.

Rescue a Method

Instead of try/catch in PHP, Ruby has begin/rescue. The way they work is essentially identical, with PHP 5.6 even getting finally, to match Ruby’s ensure.

PHP and Ruby can both recover from an exception anywhere, following their respective try or begin keywords, but Ruby can do something really clever: you can skip the begin method, and rescue directly from a function/method body:

Ruby

def create(params)
  do_something_complicated(params)
  true
rescue SomeException
  false
end

If things go wrong, an error can be handled somehow instead of bubbling up and forcing the callee to handle it. Not always what you want, but it’s handy to have the option available, and without needing to indent the whole thing to wrap in a begin.

In PHP this does not work, but the feature could look a little something like this if implemented:

function create($params) {
  do_something_complicated($params);
  return true;
} catch (SomeException $e) {
  return false;
}

While it might not be wildly important, there are a lot of nice little touches like this that make Ruby feel like it wants to help you.

Exception Retries

A few months ago I spotted a really handy feature that I never noticed before, the retry keyword:

begin
  SomeModel.find_or_create_by(user: user)
rescue ActiveRecord::RecordNotUnique
  retry
end

In this example, a race condition flares up because the find_or_create_by is not atomic (the ORM does a SELECT and then INSERT) which, if you’re really unlucky, can lead to a record being created by another process after the SELECT but before the INSERT.

As this can only happen once you can simply instruct the begin...rescue to try it again, and it will be found with the SELECT. In other examples, you’d probably want to put some logic in place to only retry once or twice, but let’s just ignore that for a second.

Focus on how annoying it would be to take one piece of the code and try it again. In Ruby you can do this:

def upload_image
  begin
    obj = s3.bucket('bucket-name').object('key')
    obj.upload_file('/path/to/source/file')
  rescue AWS::S3::UploadException
    retry
  end
end

PHP would require you to create a new function/method just for the contents of the begin block:

function upload_image($path) {
  $attempt = function() use ($path) {
    $obj = $this->s3->bucket('bucket-name')->object('key');
    $obj->upload_file($path);
  };
  
  try {
    $attempt();
  } catch (AWS\S3\UploadException $e)
    $attempt();
  }
}

Again, yes, you’d want to put some boilerplate into both to stop infinite loops, but the Ruby example is certainly much cleaner at retrying the code.

A little birdie tells me this feature is actively being developed as an RFC which will hopefully be announced soon. It could theoretically be a PHP 7.1 feature if the process goes well.

More from this author

Final Thoughts

Dabbling with Ruby in the past, I was mostly just writing Ruby like PHP. Working with a team of amazing and extremely experienced Ruby developers for the past year has taught me a lot of Rubyisms and practices that are a little different, and I don’t hate it.

This article points out things I would miss about Ruby if I went back to working with PHP, but that wouldn’t stop me from doing it. What the PHP haters regularly ignore is the progress being made by the PHP core contributors, and whilst they might not have feature X or Y that I like from Ruby, they have done some amazing things for PHP 7 and PHP 7.1 looks full of interesting surprises.

PHP has made strong plays towards consistency, with uniform variable syntax, a context-sensitive lexer, and an abstract syntax tree. All of this makes PHP as a whole more consistent, regardless of the inconsistencies in the standard library.

While the standard library isn’t going to be fixed any time soon, if PHP could add a few handy features and sprinklings of syntactic sugar like the ones above, then it would be very nice indeed.

Other languages can blaze off in all directions working on new theories, experimenting, making cool stuff that gets the HackerNews types happy, then the stuff that makes sense for PHP to take is eventually grabbed. I like this approach. After all, PHP is a pillaging pirate.

Play with as many languages as you have time and interest in playing with. Ruby is a good start, Golang is a lot of fun and Elixir is quirky but a good challenge, but don’t feel the need to jump ship from one to the other. You can write in a few, and it keeps your brain nice and active.

  • Prosper

    Wow, I thought i was the only one that saw that @Stephen Coakley:disqus . Interesting article Phil, I love it. One minor error, var_log() is also not a PHP in-built function, I guess you meant var_dump().

    • philsturgeon

      Ha, yeah I meant var_dump(). My brain was probably conflating with console.log(). Gotta stop switching languages.

      • Prosper

        Lol..it happens everytime with me too!

        • `composer require –dev symfony/var-dumper`
          and now you can use dump() which is easier to remember and in most cases better in practice.
          `dump($foo);`

          • philsturgeon

            You’re recommending a slightly better dump function, the article is saying that dumping in most cases is a weak approach to debugging compared to interactive debuggers.

  • Chris Bell

    After going full time in JS for a good while, coming back to PHP I recognised how verbose it was to create basic structures (objects and arrays). Would really like to see some more syntactic sugar in PHP; square brackets was a good improvement. Seems trivial, but when you’re writing it every day, it can become a little tiresome when you know how easy it is in other languages.

    • Jim Dawkins

      I agree. Im working in rails now an although it has some performance issues the syntax is sweet.

  • andreliem

    Great article, been waiting for an article like this for a long time from someone who has experience with both languages at a deeper level. I personally think type hinting is a strength of PHP and without it makes it a weaker choice over RoR….

  • Fred@Bootstrap

    Nice article but I can’t believe you didn’t mention the main thing that differentiates Ruby from PHP and most other languages: Blocks / Procs / Lambdas.

    • philsturgeon

      They’re ok, but they’re not mind-blowing. Blocks are mostly used the same way as callbacks are used in PHP, and whilst procs are pretty cool I still don’t use them for much more than AR scopes and lets.

      There will be a lot of features that people love and they’ll think “WTF Why no X” but everyone has their own favourite things, :)

    • philsturgeon

      They’re ok, but they’re not mind-blowing. Blocks are mostly used the same way as callbacks are used in PHP, and whilst procs are pretty cool I still don’t use them for much more than AR scopes and lets.

      There will be a lot of features that people love and they’ll think “WTF Why no X” but everyone has their own favourite things, :)

  • Davide Borsatto

    Lerdorf has become more and more of an a**hole. He behaves as if PHP was still something he had complete control over and the rest of the world just had to suck it up and as he pleases.
    That’s the same about the error message T_PAAMAYIM_NEKUDOTAYIM, where some of his reasons for sticking with the insanely absurd name were “I like it this way”, “a Google search will fix it” and “there are many PHP devs who speak Hebrew”, which coincidentally shows him contradicting himself in the motivation for not adding unless.
    He still think of PHP as the toy he created, which is definitely not any more. I’m thankful for all he’s done, but right now he’s just holding PHP back.

    • SamDark

      Nope.

      1. He’s the one fixing most of recent segfaults we’ve reported in no time. So despite not being critical to PHP existence, PHP would definitely lose major contributor if he’d decide to leave.
      2. All the important PHP decisions are made by RFCs and voting. Rasmus has only one vote.

  • Grzegorx

    What about the performance, the scalability?

    • Kevin Nagurski

      Performance of PHP is really all about the deployment (apache/nginx/op cache etc etc). Both PHP and Ruby can run extremely quickly. Scalability is also all about the deployment. Remember Facebook is PHP (well, hack, but same diff, it’s more about the WAY they run it, not that they run it).

  • Kevin Nagurski

    Good article. It’s a shame that the web dev world often comes to blows over “which is better” articles. It’s like discussing whether a Kia or Hyundai is better; they’re both cars, chose the one you like better, it doesn’t make the other worse.

    One little thing to point out, in the section about predicate methods, you say `$object === nil` for PHP. I think you meant `$object === null` or better `isnull($object)` (or `!isset($object)` or `!empty($object)`).

    • SamDark

      Kia and Hyundai are technically the same cars with a bit different internal appearence ;)

      • Kevin Nagurski

        Lol, I was wondering if anyone would pick up on that. It’s not completely true though. The i30 is based on the chassis and engine of the C’eed, but there are quite a few differences; kinda like Ruby and PHP.

        • SamDark

          I own C’eed.

          • Kevin Nagurski

            I own an i30 :-)

  • philsturgeon

    I am discussing the language itself, not the implementation. Implementation and other aspects of the stack play a much larger role in performance than the language itself. CRuby and JRuby perform very differently indeed, so that would be irrelevant.

    I’m not sure what “scalability availability” or “integrateability” mean in this context.

  • The way PHPStorm enables me to use static code checking via type hinting made me quit Ruby completely. I can’t see any further need for Ruby (in the WebDev-Space) as long as I have Scala(.js), TypeScript/Dart/JS and … PHP(Storm). IMHO PHP alone is crap.

  • Aleksander Koko

    Finally a post that is not written with anger in mind and not having sides. I think it’s time to put aside those angry disqustions on which is better. And thanks because now I have a link to send to my friends and those anonymous guys on the internet that keep trolling PHP for needle haystack problems. Good article.

  • I’d imagine the retry php equivalent should rather look something like this:
    try {
    retry: // do something,
    // possibly multiline
    } catch (Exception $e) {
    goto retry;
    }
    Otherwise you’re only retrying once.

    • philsturgeon

      Yep but using goto will bring in the velociraptors.

  • Strictly speaking this

    {‘one’: 1, ‘two’: 2, ‘three’: 3}

    is not the same as

    {‘one’ => 1, ‘two’ => 2, ‘three’ => 3}

    because it actually results in this

    {:one => 1, :two => 2, :three => 3}

    where a value started with a colon is called a symbol.

    • philsturgeon

      Yep, but PHP doesn’t have a concept of symbols and I’m not trying to baffle readers who are not initiated with Ruby.

      • Dave Mayo

        I dunno, as someone who knows both languages, but started with PHP, this would have baffled me in the following ways:

        1. It doesn’t do what you say it does, even by analogy. The object created uses object semantics for access ($obj->prop), which would be equivalent to something like OpenStruct or something with method_missing abuse that responded to obj.prop in Ruby. The object you’re trying to create here responds to [] and []=, which makes it directly like a PHP Array (from the PHP perspective).
        2. It doesn’t work, even if it did what you said it did. The ruby example errors out as copy-pasted with “SyntaxError: unexpected ‘:'”, because whitespace isn’t allowed between the key and its trailing colon.

        • philsturgeon

          1. I don’t know what point you are making here.

          2. Ha, that multi line hash sure does error. It’s not particularly important to the point that was being made. I’m not trying to teach PHP developers Ruby, I’m highlighting that Ruby continues to simplify syntax over time, going from verbose to simple to even more simple, instead of just saying “Nah this first thing is fine.”

          • Dave Mayo

            1. You’re trying to point out an equivalence between the constructs in both languages, right? The whole point of the PHP you have there is to generate Objects, as opposed to Arrays. You literally wouldn’t do it at all if you didn’t want Objects, right? You’d just make a nested array.

            So it’s really confusing that it’s compared to something that makes the Ruby equivalent of a nested Array. Especially when you have an example of the same mechanism (colon-separated hashes) described correctly right above!

            2. Fair enough, although I strongly believe that a fair portion of your audience is gonna be running the examples on a local machine to compare them while reading. I did now, and can say for sure that I would have in my days as a fulltime PHP dev.

            Overall, I really like your article’s intent, it’s clearly written, and I think you have a lot of good stuff here. But if you can correct these two parts, I think it would make it a lot stronger, and I think they do 100% represent actual problems with the article.

          • philsturgeon

            1. Ruby has Hashes, Lists and Objects. PHP has Arrays to cover both Hashes and Lists, and Objects separately. The “Object Literals” section could be called “Hash Literals” but then that wouldn’t make much sense to PHP developers would it :) I definitely didn’t say that { } is an object in Ruby.

            In Ruby you use a hash for a lot of what you would use a stdClass for in PHP, and creating them is far far easier in Ruby. At least until the Object Literal RFC is implemented.

            Clear?

            2. The error message they get is pretty clear, so I’m not too worried about that. :)

          • Dave Mayo

            1. Here’s the thing – as far as I know, the values of using a stdClass instead of an Array are:
            A.) An object can have members that are direct function calls – $obj->function()
            B.)Some PHP functions expect an object without caring about type, and this lets you basically pass arrays to such functions.

            I haven’t done PHP full time in a few years, but this is all I ever used cast-to-object or stdClass for. Please let me know if I’m missing something here!

            Meanwhile, the Ruby there:
            A.) Can’t be a target for direct function calls. You can’t do hsh[:thing] where thing resolves to a proc/lambda/etc, and have it run the method. You’d have to do hsh[:thing].call
            B.) A hash in ruby isn’t going to satisfy something that expects an object with accessor methods. If something expects to go object.key, it’s going to blow up if you pass it {key: “value”}

            And I’d argue that, while you’re not exactly SAYING that {} is an object in Ruby, you are saying that {“key” : “value”} is the Ruby way to do what the Object Literal RFC does. Which is create objects. Which means that, by direct inference, you’re kinda saying that {} creates an object in Ruby.

            2. Your call, of course, but it seems like a weirdly easy-to-fix issue to decide “Oh, I’ll just let my code I’m putting up as an example cause an error when run.” Rightly or wrongly, people are going to side-eye that – if it were me, I’d either delete the trailing spaces, or put a notice that the code doesn’t run as written.

  • mehmet

    Thanks for article really. It’s pretty enough about code comparing. But code not enough about community effect when you want to choose ruby or php. Ruby gems really stable but gem manager really slow. PHP has many composer package but these bundles can’t live without really community support. I think if you have real budged use ROR, but you want to try something and pay less use PHP. But if you are really serious ( for example finance tools ) trust the big boy java. Everyone have choose own way for own project.

  • mehmet

    Thanks for article really. It’s pretty enough about code comparing. But code not enough about community effect when you want to choose ruby or php. Ruby gems really stable but gem manager really slow. PHP has many composer package but these bundles can’t live without really community support. I think if you have real budged use ROR, but you want to try something and pay less use PHP. But if you are really serious ( for example finance tools ) trust the big boy java. Everyone have choose own way for own project.

    • I think this a good point. The right tool for the right job is something to keep in mind on every project.

  • IDontWannaDie

    Grammar nitpick:

    > “allow rockets to be replaced with semi-colons,”

    Should be

    > “allow rockets to be replaced with colons,”

  • Hey Phil! This was really nice. I’m just starting to transition into some rails from laravel and these comparisons are great. The only thing I didn’t follow was your short object definition. I was led to believe that syntax is a hash which is essentially an associative array in php? True or false. I’d love to understand this more

  • I loved you with Writing API you won’t hate, now I love you more with this post, right after i’m learning ruby with php background. Thanks alot @philsturgeon:disqus

  • Alejandro Hernandez

    Excellent post, i think is one of the best way to talk about Ruby and php to compare both of them

Recommended
Sponsors
Get the latest in PHP, once a week, for free.