1

I've got a SelectQuery which I've created using db_select(). Then, after I've executed the query, I'm trying to clone it as I need to generate a few more queries based on the original one.

However, for some reason the clones I get from the original query doesn't seem to be clones. This is what I do.

// Create query
$q0 = db_select('track', 't');
$q0->fields('t', array('id','number','title');
[...]
$tracks = $q0->execute()->fetchAll();

// Clear fields on original query.
$fields = &$q0->getFields();
$fields = array();

// Clone original query. The below queries should not have
// any fields set as they just got cleared above.
$q1 = clone $q0;
$q2 = clone $q0;

// This gets weird. The queries $q1 and $q2 should be separate
// clones, independent of each other. So should their fields. 
// However, setting fields on $q1 also sets fields on $q2.
$q1->fields('t', array('id'));

// Output : Array ( [id] => Array ( [field] => id [table] => t [alias] => id ) )
print_r($q2);

The fields() function on SelectQuery simply sets an array (see below). I thought that cloning an instance of a class containing an array would copy those arrays by value...and not by reference? Is this a special cloning "feature"?

protected $fields = array();

public function &getFields() {
  return $this->fields;
}

1 Answer 1

1

As you have seen in bug report #1671848 the special getters of these special drupal objects breaks the clone behavior. The problem is that by reference getter are used and this imply hazardous behaviors in PHP internals of returned values.

I think it will be quite very long until this bug get fixed. So one of the solution is to avoid such writings:

$fields = &$q0->getFields();
$fields = array();

This is not the way to empty something in an object. here the & is the fault. after such a write the internal array stored in the object is broken and the object record it as a reference, you've been breaking object encapsulation and bad things happen (sse the bug report). Use a setter, And if there is not setter to do that clone the queries before havinf any field added to the query (so it's empty).

2
  • Thanks for your reply, and for your advise! As a side note : I'm tempted to say that it is more bad design than it is bad usage. After all, it should be the responsibility of the SelectQuery to manage it's internals, and not my responsibility (it is a black box - I don't know what's going on inside it). The documentation even says that the method returns an array as reference for hooks to modify it, and clearing the array would strictly be a modification too. Anyway; it's how it is and I've got to find another way :-) Have a good day!
    – sbrattla
    Commented Sep 3, 2012 at 14:03
  • You're right on that.
    – regilero
    Commented Sep 3, 2012 at 14:20

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.