protected function _callDynamic(array $expression, CompilationContext $compilationContext)
{
$variable = $compilationContext->symbolTable->getVariableForRead($expression['name'], $compilationContext, $expression);
switch ($variable->getType()) {
case 'variable':
case 'string':
break;
default:
throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as dynamic caller", $expression['left']);
}
/**
* Resolve parameters
*/
if (isset($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
} else {
$params = array();
}
$codePrinter = $compilationContext->codePrinter;
/**
* Process the expected symbol to be returned
*/
$this->processExpectedObservedReturn($compilationContext);
/**
* At this point the function will be called in the PHP userland.
* PHP functions only return zvals so we need to validate the target variable is also a zval
*/
$symbolVariable = $this->getSymbolVariable();
if ($symbolVariable) {
if (!$symbolVariable->isVariable()) {
throw new CompilerException("Returned values by functions can only be assigned to variant variables", $expression);
}
/**
* We don't know the exact dynamic type returned by the method call
*/
$symbolVariable->setDynamicTypes('undefined');
}
/**
* Include fcall header
*/
$compilationContext->headersManager->add('kernel/fcall');
/**
* Add the last call status to the current symbol table
*/
$this->addCallStatusFlag($compilationContext);
/**
* Call functions must grown the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if (!isset($expression['parameters'])) {
if ($this->isExpectingReturn()) {
if ($symbolVariable->getName() != 'return_value') {
if ($this->mustInitSymbolVariable()) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
}
$compilationContext->backend->callDynamicFunction($symbolVariable, $variable, $compilationContext);
} else {
$compilationContext->backend->callDynamicFunction(null, $variable, $compilationContext);
}
} else {
if (count($params)) {
if ($this->isExpectingReturn()) {
if ($symbolVariable->getName() != 'return_value') {
if ($this->mustInitSymbolVariable()) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
}
$compilationContext->backend->callDynamicFunction($symbolVariable, $variable, $compilationContext, $params);
} else {
$compilationContext->backend->callDynamicFunction(null, $variable, $compilationContext, $params);
}
} else {
if ($this->isExpectingReturn()) {
if ($symbolVariable->getName() != 'return_value') {
if ($this->mustInitSymbolVariable()) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
}
$compilationContext->backend->callDynamicFunction($symbolVariable, $variable, $compilationContext);
} else {
$compilationContext->backend->callDynamicFunction(null, $variable, $compilationContext);
}
}
}
/**
* Temporary variables must be copied if they have more than one reference
*/
foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
$codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
}
$this->addCallStatusOrJump($compilationContext);
/**
* We can mark temporary variables generated as idle
*/
foreach ($this->getTemporalVariables() as $tempVariable) {
$tempVariable->setIdle(true);
}
if ($this->isExpectingReturn()) {
return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
}
return new CompiledExpression('null', null, $expression);
}