*/
public function enterNode(Node $node)
{
- // TODO: support MethodCall and StaticCall as well.
+ // @todo support MethodCall and StaticCall as well.
if ($node instanceof FuncCall) {
- $name = $node->name;
-
// if function name is an expression or a variable, give it a pass for now.
- if ($name instanceof Expr || $name instanceof Variable) {
+ if ($node->name instanceof Expr || $node->name instanceof Variable) {
return;
}
+ $name = (string) $node->name;
+
+ if ($name === 'array_multisort') {
+ return $this->validateArrayMultisort($node);
+ }
+
try {
- $refl = new \ReflectionFunction(implode('\\', $name->parts));
+ $refl = new \ReflectionFunction($name);
} catch (\ReflectionException $e) {
// Well, we gave it a shot!
return;
if (array_key_exists($key, $node->args)) {
$arg = $node->args[$key];
if ($param->isPassedByReference() && !$this->isPassableByReference($arg)) {
- throw new FatalErrorException(self::EXCEPTION_MESSAGE);
+ throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
}
}
}
$arg->value instanceof MethodCall ||
$arg->value instanceof StaticCall;
}
+
+ /**
+ * Because array_multisort has a problematic signature...
+ *
+ * The argument order is all sorts of wonky, and whether something is passed
+ * by reference or not depends on the values of the two arguments before it.
+ * We'll do a good faith attempt at validating this, but err on the side of
+ * permissive.
+ *
+ * This is why you don't design languages where core code and extensions can
+ * implement APIs that wouldn't be possible in userland code.
+ *
+ * @throws FatalErrorException for clearly invalid arguments
+ *
+ * @param Node $node
+ */
+ private function validateArrayMultisort(Node $node)
+ {
+ $nonPassable = 2; // start with 2 because the first one has to be passable by reference
+ foreach ($node->args as $arg) {
+ if ($this->isPassableByReference($arg)) {
+ $nonPassable = 0;
+ } elseif (++$nonPassable > 2) {
+ // There can be *at most* two non-passable-by-reference args in a row. This is about
+ // as close as we can get to validating the arguments for this function :-/
+ throw new FatalErrorException(self::EXCEPTION_MESSAGE, 0, E_ERROR, null, $node->getLine());
+ }
+ }
+ }
}