Referencing an array in a variable object property

Update:
Thanks to an anonymous commenter for letting me know that this is an issue of operator precedence.

This is more a personal note than anything, but I've been banging my head against a wall trying to figure out how to reference an array within a variably-named object property in PHP. Having not found anything very useful when search Google, I figure my post may end up being someone's helpful search result. Maybe I just don't know the right terminology for what I'm trying to do...?

Anyways, I've got a module that needs to modify the string in a CCK text field before it's shown to users on the node edit form. It's a "glue" module that helps us handle course enrollment, and the field in question handles course instructor(s) via a comma-delimited list of usernames. The module takes the user's submitted data, parses it into an array and stores each username in a table joined with course ID for other uses (such as passing to our Sakai installation). The CCK field is referenced in several places, so I use an admin settings form to allow us to say, "This CCK field is the field that users fill out to define instructors." This allows us to avoid hard-coding the CCK field name all over our glue module, but it also led to the headache I encountered today.

When a user goes back to the form to edit the course, I want to present the username list cleanly (alphabetical, no accidental whitespace, etc). Here's the code I tried to use:

function ideal_courses_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  // ... (irrelevant stuff here)

    case 'prepare':
      $field_instructors = variable_get('ideal_courses_field_instructors', NULL);
      // The line that fails is below:
      $node->$field_instructors[0]['value'] = ideal_courses_instructors_as_string($node);
    break;

  // ... (more irrelevant stuff here)
}

The error I kept getting was, "PHP Fatal error: Cannot use string offset as an array." The strange thing is that doing a print_r($node->$field_instructors); works fine. The fix was simple, but difficult to find: wrap the variable property name in curly braces: $node->{$field_instructors}[0]['value']. The full result is below:

function ideal_courses_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  // ... (irrelevant stuff here)

    case 'prepare':
      $field_instructors = variable_get('ideal_courses_field_instructors', NULL);
      // Fixed line is below:
      $node->{$field_instructors}[0]['value'] = ideal_courses_instructors_as_string($node);
    break;

  // ... (more irrelevant stuff here)
}

Comments

Actually, the reason it didn't work is because of operator precedence. PHP evaluated the $field_instructors[0]['value'] as a unit first, since [] is very high in the precedence order, and then that expression was then evaluated as $node->{result of expression} where {result of expression} is whatever $field_instructors[0]['value'] evaluates to. It looks like you meant to evaluate first the $node->$field_instructors part first to get a reference to that variable in the object, and then perform the array operations. It's exactly the same problem that makes $a + $b * $c evaluate to something different than ($a + $b) * $c.The curly braces force the precedence to be evaluated in a different order. I imagine that parentheses would've worked too, though I haven't actually tried it with this specific example.

See here for a table of operators and their precedence: http://php.net/operators

Thanks for the details. I actually hadn't ever used the curly brace {expression} syntax before and didn't even know it existed. It makes sense it's something as simple as operator precedence. Thanks for clearing that up!

Thanks to both of you for explaining this. I have had the same confusion and previously dealt with it by adding an extra line to break the assignment into an extra step.

This is really useful to know. I never knew object names could be referenced like that. Thanks for posting. It's knowing these little details that can add up to doing really interesting stuff.

i think the poster is correct as to why it fails; but i think is suggesting a solution like:

{$node->$field_instructors}[0]['value']

and that doesn't actually work.

I have always split this into 2 statements; but that doesn't work too well for statements.

I am plenty capable at html and javascript, as well as CSS, but I was wondering if now that our company will be going to a Drupal platform, will I need to know PHP?

Also, if I were to set up my own music website on Drupal, would I need to know PHP?

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.