Variable Arguments

  • published on February 13th, 2008

    Rails uses quite a few techniques to make the end-user API a little nicer when you’re creating your applications. One of these techniques is having a method accept variable arguments with a hash of options. We see this pattern appear in quite a few different areas of the Rails API, particularly in ActiveRecord and ActionView.

    An an example, we can specify a variable number of attributes when we perform model validation. Take a look at how we validate the presence of both the name and age attributes for a model along with a custom error message as the final argument.

    Ruby

    class User < ActiveRecord::Base
      validates_presence_of :name, :age, :message => "Can't be empty!"
    end

    We also see this pattern used in various built-in view helper methods. When we want to include multiple stylesheets in our application, we can specify multiple sources using stylesheet_link_tag.

    Ruby

    <head>
      <%= stylesheet_link_tag :layout, :colors, :media => "screen" %>
    </head>

    Using variable arguments is often more convenient than calling a function multiple times, and it is a little nicer than passing an array. This trick can be adapted to PHP development pretty easily. The above example looks quite different from PHP when using the common Ruby style.

    However, it does map faithfully to PHP if we add back the syntactic noise that we purposely left out. We also talk about this transliteration in the Beginning Ruby Code chapter of the book.

    Ruby

    <%= stylesheet_link_tag(:layout, :color, {:media => "screen"}) %>

    PHP

    <?= stylesheetLinkTag('layout', 'color', array('media' => 'screen')) ?>

    In PHP we implement variable arguments using using the func_get_args() function:

    PHP

    function stylesheetLinkTag($sources)
    {
        $sources = func_get_args();
     
        foreach ($sources as $source) {
          // ...
        }
    }

    Since the $sources come from func_get_args(), no arguments in the function definition are necessary. However, if the function definition has no arguments, PHP will not raise a notice if the function is called with no arguments. Since our function requires at least one argument, it’s useful to have it in the function definition for that reason. It will also get picked up by code documentation tools.

    Let’s not forget about the optional list of options that we pass in as the final argument. We can extract this data in our PHP function implementation by simply checking if the last value of the variable arguments is an array.

    PHP

    function stylesheetLinkTag($sources)
    {
      $sources = func_get_args();
      $last    = end($sources);
      $options = is_array($last) ? array_pop($sources) : array();
     
      // find the stylesheet media attribute
      $media = isset($options['media']) ? $options['media'] : '';
     
      foreach ($sources as $source) {
        // ...
      }
    }

Post a comment


We welcome your participation but please note we reserve the right to remove any comments that we think are not relevant or do not contribute to the discussion.