Zephir\FunctionCall::_callNormal PHP Method

_callNormal() protected method

protected _callNormal ( array $expression, zephir\CompilationContext $compilationContext )
$expression array
$compilationContext zephir\CompilationContext
    protected function _callNormal(array $expression, CompilationContext $compilationContext)
    {
        $funcName = strtolower($expression['name']);
        if ($funcName == 'array') {
            throw new CompilerException("Cannot use 'array' as a function call", $expression);
        }
        /**
         * Try to optimize function calls using existing optimizers
         */
        $compiledExpr = $this->optimize($funcName, $expression, $this, $compilationContext);
        if (is_object($compiledExpr)) {
            return $compiledExpr;
        }
        $exists = true;
        if (!$this->functionExists($funcName, $compilationContext)) {
            $compilationContext->logger->warning("Function \"{$funcName}\" does not exist at compile time", "nonexistent-function", $expression);
            $exists = false;
        }
        /**
         * Static variables can be passed using local variables saving memory if the function is read only
         */
        if ($exists) {
            $readOnly = $this->isReadOnly($funcName, $expression);
        } else {
            $readOnly = false;
        }
        /**
         * Resolve parameters
         */
        if (isset($expression['parameters'])) {
            if ($readOnly) {
                $params = $this->getReadOnlyResolvedParams($expression['parameters'], $compilationContext, $expression);
            } else {
                $params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
            }
        } else {
            $params = array();
        }
        /**
         * Some functions receive parameters as references
         * We mark those parameters temporary as references to properly pass them
         */
        $this->markReferences($funcName, $params, $compilationContext, $references, $expression);
        $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');
            $symbol = $compilationContext->backend->getVariableCodePointer($symbolVariable);
        }
        /**
         * Include fcall header
         */
        $compilationContext->headersManager->add('kernel/fcall');
        /**
         * Call functions must grown the stack
         */
        $compilationContext->symbolTable->mustGrownStack(true);
        /**
         * Check if the function can have an inline cache
         */
        $functionCache = $compilationContext->cacheManager->getFunctionCache();
        $cachePointer = $functionCache->get($funcName, $compilationContext, $this, $exists);
        /**
         * Add the last call status to the current symbol table
         */
        $this->addCallStatusFlag($compilationContext);
        if (!count($params)) {
            if ($this->isExpectingReturn()) {
                if ($symbolVariable->getName() == 'return_value') {
                    $codePrinter->output('ZEPHIR_RETURN_CALL_FUNCTION("' . $funcName . '", ' . $cachePointer . ');');
                } else {
                    if ($this->mustInitSymbolVariable()) {
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->trackVariant($compilationContext);
                    }
                    $codePrinter->output('ZEPHIR_CALL_FUNCTION(' . $symbol . ', "' . $funcName . '", ' . $cachePointer . ');');
                }
            } else {
                $codePrinter->output('ZEPHIR_CALL_FUNCTION(NULL, "' . $funcName . '", ' . $cachePointer . ');');
            }
        } else {
            if ($this->isExpectingReturn()) {
                if ($symbolVariable->getName() == 'return_value') {
                    $codePrinter->output('ZEPHIR_RETURN_CALL_FUNCTION("' . $funcName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');');
                } else {
                    if ($this->mustInitSymbolVariable()) {
                        $symbolVariable->setMustInitNull(true);
                        $symbolVariable->trackVariant($compilationContext);
                    }
                    $codePrinter->output('ZEPHIR_CALL_FUNCTION(' . $symbol . ', "' . $funcName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');');
                }
            } else {
                $codePrinter->output('ZEPHIR_CALL_FUNCTION(NULL, "' . $funcName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');');
            }
        }
        /**
         * Temporary variables must be copied if they have more than one reference
         */
        foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
            $codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
        }
        if (is_array($references)) {
            foreach ($references as $reference) {
                $variable = $compilationContext->symbolTable->getVariable($reference, $compilationContext);
                $compilationContext->codePrinter->output('ZEPHIR_UNREF(' . $compilationContext->backend->getVariableCode($variable) . ');');
            }
        }
        $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);
    }