0

I have a method that extends the execute() method used in the Drupal 7 database abstraction layer.

When used with db_query, such as:

$result = my_extended_db_query("SELECT * FROM {node} WHERE nid<100")->execute();

$result holds a DatabaseStatementBase object, whether there are resulting rows or not. However, following:

return $result;

the calling function receives an empty array if there had been no query results, instead of a DatabaseStatementBase object. Because of this, ->fetchAll() fails because it is attempting to operate on a non-object.

How do I get my return to arrive as the same object is started as?

The method:

public function execute() {
$sql = $this->sql;
switch ($this->function) {
  case 'db_query':
    if ($this->args) {
      $args = $this->args;
      uksort($args,"si_stats_sort_by_length");
      foreach($args as $name => $value) {
        $sql = str_replace("{" . $name . "}",$value,$sql);
        if (is_array($value)) {
          $sql = str_replace($name,"('" . implode("', '",$value) . "')",$sql);
        } else {
          $sql = str_replace($name,"'" . str_replace("'","''",$value) . "'",$sql);
        }
      }
      try {
        $query = db_query($sql);
      }
      catch (Exception $e) {
        // log the error
        $msg = $e->getMessage() . "\n";
        $msg .= $e->getTraceAsString() . "\n";
        mylog($msg . PHP_EOL . PHP_EOL . $sql, debug_backtrace(), LOG_ERROR);
      }
      return $query;
    } else {
      try {
        $query = db_query($sql);
      }
      catch (Exception $e) {
        // log the error
        $msg = $e->getMessage() . "\n";
        $msg .= $e->getTraceAsString() . "\n";
        mylog($msg . PHP_EOL . PHP_EOL . $sql, debug_backtrace(), LOG_ERROR);
      }
      return $query;
    }
7
  • That isn't possible - whatever my_extended_db_query returns will be the same whether you save it in a local var or return it from a function; this is the nature of PHP, no Drupal-discipline involved. The only way that could be different is if you have a PHP extension installed which messes with return values from functions
    – Clive
    Commented Jan 22, 2015 at 15:09
  • "It isn't possible" isn't particularly helpful in the face of it happening. It seems that the issue is when the result set is empty, the variable holds an interface, and an interface cannot be returned.
    – JAyenGreen
    Commented Jan 22, 2015 at 15:18
  • To be fair I did give you a scenario where it could be possible, but you'll need to check that in the context of your server. What I'm saying is that between $x = some_function(); return $x;, it's not possible, through core PHP at least, for the two versions of $x to be different. They are the same by definition. The var will never hold an interface, always an instance of a class which subscribes to that interface. An interface cannot be instantiated, so you can never have an instance of it, thus a variable can never contain one
    – Clive
    Commented Jan 22, 2015 at 15:23
  • Right, but there's no extension messing with it. I believe even in core php an interface and a class cannot be returned, as they cannot be instantiated. It seems that an empty result set is an interface of type DatabaseStatementBase, and in attempting to return an interface, the result is an empty array.
    – JAyenGreen
    Commented Jan 22, 2015 at 15:25
  • Nope, it's an instance of a class, whose definition implements an interface. DatabaseStatementBase is not an interface FYI, it's a class. Your class will inherently implement DatabaseStatementInterface through DatabaseStatementBase, but other than that, interfaces are not involved in what you're talking about
    – Clive
    Commented Jan 22, 2015 at 15:27

1 Answer 1

0

Bandaid fix, instead of return $query; test to see if the class of $query is of DatabaseStatementBase or else create a new empty instance of that class and return that ... Eg:

if (is_a($query, 'DatabaseStatementBase')) {
   return $query;
} else {
  return $empty = new DatabaseStatementBase(Database::getConnection());
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.