Thursday 26 January 2012

Where the **** is it?

You know how it is? You have this complex and massive PHP structure with recursive elements and somewhere in all that is a value you're looking for. Views object I'm looking at you!

Here's a PHP routine, which is not Drupal specific, that will dig down into an object to find the property or array item you're looking for - and it avoids recursion by keeping a list of structures it's already searched by MD5ing the serialized version of the structure.

The parameters are the initial structure to search; the property you're looking for - it can be partial if you're not sure what the property is called; $id would usually be the identifier of the structure you're supplying and $depth should be ignored. It returns an array of strings that show the way into the structure to find the property. It's quite common to get multiple results.

One thing to watch out for: If your structure is recursive (like a Views object) and you start the search deeper into the structure with the idea that you'll shorten the search? Well you might, but if it's recursive you might also end up going into one of the recursed objects because the routine hasn't seen it before.

Anyway, with that in mind, here it is:


function common_locate($struct, $seek, $id = '', $depth = 0) {
  static $structs = array(), $results = array();
  if (is_array($struct) || is_object($struct)) {
    $struct = (array) $struct;
    foreach ($struct as $key => $value) {
      if (strpos($key, $seek)!==FALSE) {
        $results[] = "$id => $key = $value";
      }
      if (is_array($value)) {
        $idx = str_replace('0', 'g', md5(serialize($value)));
        if (!isset($structs[$idx])) {
          $structs[$idx] = "$key:$depth";
          common_locate($value, $seek, "{$id}[$key]", $depth+1);
        }
      }
      elseif (is_object($value)) {
        $idx = str_replace('0', 'g', md5(serialize($value)));
        if (!isset($structs[$idx])) {
          $structs[$idx] = "object:$key:$depth";
          common_locate($value, $seek, "{$id}->$key", $depth+1);
        }
      }
    }
  }
  return $results;
}

No comments: