{"record":{"id":"a30d39156939855d","repo":"yiisoft/yii2","slug":"the-arrayexpression-class-can-not-be-iterated-when","errorCode":null,"errorMessage":"The ArrayExpression class can not be iterated when the value is a QueryInterface object","messagePattern":"The ArrayExpression class can not be iterated when the value is a QueryInterface object","errorType":"exception","errorClass":"yii\\base\\InvalidConfigException","httpStatus":null,"severity":"error","filePath":"framework/db/ArrayExpression.php","lineNumber":199,"sourceCode":"    {\n        return count($this->value);\n    }\n\n    /**\n     * Retrieve an external iterator\n     *\n     * @link https://www.php.net/manual/en/iteratoraggregate.getiterator.php\n     * @return Traversable An instance of an object implementing <b>Iterator</b> or\n     * <b>Traversable</b>\n     * @since 2.0.14.1\n     * @throws InvalidConfigException when ArrayExpression contains QueryInterface object\n     */\n    #[\\ReturnTypeWillChange]\n    public function getIterator()\n    {\n        $value = $this->getValue();\n        if ($value instanceof QueryInterface) {\n            throw new InvalidConfigException('The ArrayExpression class can not be iterated when the value is a QueryInterface object');\n        }\n        if ($value === null) {\n            $value = [];\n        }\n\n        return new \\ArrayIterator($value);\n    }\n}\n","sourceCodeStart":181,"sourceCodeEnd":208,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/db/ArrayExpression.php#L181-L208","documentation":"ArrayExpression wraps either a concrete PHP array or a subquery (QueryInterface) for use as an SQL array literal. Its getIterator() (invoked by foreach) can only walk a real array; when the wrapped value is a QueryInterface instance there is nothing to iterate client-side, so InvalidConfigException is thrown instead of silently iterating the query object.","triggerScenarios":"foreach ($arrayExpression as $v) after constructing it with (new Query())->select('id')->from('t') as the value; passing the expression into generic helpers that iterate their input (ArrayHelper, implode, json_encode of traversables); debugging by looping over an expression built for SQL.","commonSituations":"Code that accepts array|Expression union types and hits the subquery variant; developers inspecting expression objects during query debugging; reusing a value that is sometimes an array and sometimes a subquery.","solutions":["Keep the original PHP array for iteration and use ArrayExpression only when composing SQL","Guard before iterating: $v = $expr->getValue(); if (!$v instanceof QueryInterface) { foreach ($v as ...) }","If you actually need the subquery's rows, run it (->column()/->all()) and iterate the result","Type-hint shared helpers to accept only arrays, not Traversable, when expression inputs are possible"],"exampleFix":"// before\n$expr = new ArrayExpression((new Query())->select('id')->from('tag'));\nforeach ($expr as $tagId) { ... } // throws\n\n// after\n$tagIds = (new Query())->select('id')->from('tag')->column();\nforeach ($tagIds as $tagId) { ... }\n// use new ArrayExpression($tagIds) only when embedding in SQL","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isIterableArrayExpression(\\yii\\db\\ArrayExpression $expr): bool\n{\n    $value = $expr->getValue();\n    return $value === null || !$value instanceof \\yii\\db\\QueryInterface;\n}","tryCatchPattern":"try {\n    foreach ($expr as $item) { /* ... */ }\n} catch (yii\\base\\InvalidConfigException $e) {\n    if (strpos($e->getMessage(), 'ArrayExpression') !== false) {\n        $items = (new Query())->... ->column(); // materialize the subquery instead\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Keep raw arrays for iteration; wrap in ArrayExpression only at SQL composition time","Type-hint helpers that iterate as array, not iterable","Never foreach over values that may be expression objects"],"tags":["expression","iterator","query","array","yii2"],"backgroundTag":"invalid-iteration","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}