'Unsupported operand types' in Drupal 6.x

I recently (finally) updated my blog to Drupal 6, but I was having all sorts of trouble running cron. Instead of doing all the chrony magical stuff, it kept saying things like this:

Fatal error: Unsupported operand types in [...]/drupal/includes/common.inc on line 1376
Fatal error: Unsupported operand types in [...]/drupal/includes/common.inc on line 1546

If you run into either of these errors, you've found the one of the joys of a rapidly changing api! As of Drupal 6.x, Drupal has changed the arguments for the l() and url() functions. These functions used to have a bunch of arguments for things like 'absolute', 'query', 'fragment', and so forth. The problem was when you had a fragment but no query string, or you just wanted to declare a url as absolute. You had to add a whole bunch of null arguments to get to the one you actually wanted to set. So Drupal made a wise move and combined all the options into a single argument, fittingly named  $options .

Check this out

// The old way to wrap an image in a link.
l('<img src="foo.png"/>', 'node/1', array(), null, null, null, TRUE);
 
// And the new way
l('<img src="foo.png"/>', 'node/1', array('html' => TRUE));

See how much easier the new way is?

A problem arises

The problem comes when the new functions are handed arguments intended for the old ones. I ran into it in a block and a node, both of which contained PHP snippets. Since I was upgrading the site from Drupal 5, these snippets expected the old function. And it turns out that the new function is none too happy when you pass it the wrong arguments.

And here are three options to get around it

Depending on how much mucking around in Drupal code you feel like doing, there are several ways to fix this problem.

First, you can just make things work

Here's what it'll take to make the errors go away. I wouldn't suggest using this method unless you're bypassing an error in a module you didn't write, and you don't really feel like hacking around in it to fix things. Simply drop these two snippets into drupal/includes/common.inc.

  /**
   * Add this code right after the line that says:
   *
   * `function url($path = NULL, $options = array()) {`
   *
   * (currently on line 1368)
   */
  // Convert arguments and move on...
  if (!is_array($options)) {
    $options = array();
    $args = func_get_args();
    if (isset($args[1])) $options['query'] = $args[1];
    if (isset($args[2])) $options['fragment'] = $args[2];
    if (isset($args[3])) $options['absolute'] = $args[3];
  }
 
  /**
   * And drop this surprisingly similar code right
   * after the line that says:
   *
   * `function l($text, $path, $options = array()) {`
   *
   * (currently on line 1541)
   */
  // Convert arguments and move on...
  $args = func_get_args();
  if (count($args) > 3) {
    $options = array();
    if (isset($args[2])) $options['attributes'] = $args[2];
    if (isset($args[3])) $options['query'] = $args[3];
    if (isset($args[4])) $options['fragment'] = $args[4];
    if (isset($args[5])) $options['absolute'] = $args[5];
    if (isset($args[6])) $options['html'] = $args[6];
  }

Your code should work exactly as intended. Note that this method is a dirty hack, but will get the job done (i.e. treat the symptoms). Don't come crying to me when something breaks later, because I'm warning you now.

Alternatively, you could add some logging.

This way you at least know what's happening. Just after the last of those  if (isset($args[6])) lines, add a call to  trigger_error() .

    trigger_error("Deprecated url formatter call");

This will be logged to the screen, to your server's error log, or to your database (watchdog), depending on your site configuration. Adding logging to your hack is preferred, because that way you know how often it's happening. If things get out of hand, you can always go for door number three:

Find and fix the source

For this we'll use a tool called  debug_print_backtrace() . It's a super-rad built-in PHP debugging tool that tells you exactly what call path led your app to this unfortunate end. You can wade through the calls and (probably) figure out who is to blame for your predicament. This is how I found my problems. Your mileage may vary.

Add this (instead of the argument conversion code):

  // Die.
  $args = func_get_args();
  if (!is_array($options) || count($args) > 3) {
    echo "<pre>";
    print_r($args);
    echo "</pre>";
    echo "<hr/>";
    echo "<pre>";
    debug_print_backtrace();
    die();
  }

The first chunk of output is your link builder arguments. The second, and much larger, piece is your backtrace. Your culprit is often on line #1 or #2. Mine was a call to eval (line #1), which happened because of a node with php_filter enabled (line #5)... And the arguments to line #5 were kind enough to give me a node id. Sweet! Mystery solved!

I'm not going to lie, the debug backtrace is usually a bit ugly. And it might take you a bit to find the culprit. But this is the real way to solve your unsupported operand error.

Good luck!

Comments

thanks this really helped me out

Thank you very much Justin. I've only implemented the "quick fix" to be able to edit my menus, but you saved my butt! Thank you very much for your help!

No problem. I'm glad I could help.

Thank you man. You are great help. I can't express how relieved you just made me feel with this.

Hi,

I had this issue in community_tags and fixed it for me with taking this code:
'#value' => ''. t('Login or register to tag items', array('@login' => url('user/login', $destination), '@register' => url('user/register', $destination))) .''
and changing it into:
'#value' => ''. t('Login or register to tag items', array('@login' => l('user/login', $destination), '@register' => l('user/register', $destination))) .''
in file: community_tags.pages.inc

According to: http://api.drupal.org/api/function/url
When creating links in modules, consider whether l() could be a better alternative than url().

Bye, Chris

I don't think that does what you think it does.

Genius, thanks! Your quick fix has saved my bacon.

Thanks Justin,

I struggled for 8 hours today with the problem of the operand, etc...
Now, first with the hack (I will see later) it works again!

Greetz,

Marco

THANKS!

debug_print_backtrace() helped me updating the outdated export to docbook module to drupal 6.

Thanks Justin
I want to try the debug_print_backtrace() method but I am a newbe and don't know where to write the code.can you please
tell me how to do it/run it?

Sorry, I can't help there. Using debug_print_backtrace() will only tell you where to fix the problem, not how or why... i.e. if you don't already know where to put it, you won't be able to do anything with it once it's there.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • You can use Markdown syntax to format and style the text. Also see Markdown Extra for tables, footnotes, and more.
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li>
  • Lines and paragraphs break automatically.

More information about formatting options