Zephir\Operators\Other\FetchOperator::compile PHP Method

compile() public method

public compile ( array $expression, Zephir\CompilationContext $compilationContext ) : Zephir\CompiledExpression
$expression array
$compilationContext Zephir\CompilationContext
return Zephir\CompiledExpression
    public function compile(array $expression, CompilationContext $compilationContext)
    {
        $compilationContext->headersManager->add('kernel/array');
        $variable = $compilationContext->symbolTable->getVariableForWrite($expression['left']['value'], $compilationContext, $expression['left']);
        if ($variable->getType() != 'variable') {
            throw new CompilerException('Cannot use variable type: ' . $variable->gettype() . ' in "fetch" operator', $expression);
        }
        /**
         * return_value must not be observed
         */
        if ($variable->getName() != 'return_value') {
            /*
             * @todo use a read detector here
             */
            $readOnly = false;
            $line = max($compilationContext->symbolTable->getLastCallLine(), $compilationContext->symbolTable->getLastUnsetLine());
            if ($line === false || $line > 0 && $line < $expression['line']) {
                $numberMutations = $compilationContext->symbolTable->getExpectedMutations($variable->getName());
                if ($numberMutations == 1) {
                    if ($variable->getNumberMutations() == 1) {
                        $variable->setIsInitialized(true, $compilationContext, $expression);
                        $variable->setMemoryTracked(false);
                        $variable->setDynamicTypes('undefined');
                        $readOnly = true;
                    }
                }
            }
            if (!$readOnly || $expression['right']['type'] != 'array-access') {
                $variable->setIsInitialized(true, $compilationContext, $expression);
                $variable->observeVariant($compilationContext);
                $variable->setDynamicTypes('undefined');
                $variable->setPossibleValue(new CompiledExpression('undefined', '', $expression), $compilationContext);
            }
        } else {
            $variable = $compilationContext->symbolTable->getTempVariableForObserve('variable', $compilationContext, $expression);
        }
        if ($readOnly) {
            $flags = '1';
        } else {
            $flags = '0';
        }
        switch ($expression['right']['type']) {
            case 'array-access':
                $exprVariable = new Expression($expression['right']['left']);
                $exprVariable->setReadOnly(true);
                $exprVariable->setNoisy(false);
                $exprCompiledVariable = $exprVariable->compile($compilationContext);
                if ($exprCompiledVariable->getType() != 'variable') {
                    throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as array", $expression['right']['left']);
                }
                $evalVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression['right']['left']);
                if ($evalVariable->getType() != 'variable' && $evalVariable->getType() != 'array') {
                    throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as array", $expression['right']['left']);
                }
                if ($evalVariable->getType() == 'variable') {
                    if ($evalVariable->hasDifferentDynamicType(array('undefined', 'array', 'null'))) {
                        $compilationContext->logger->warning('Possible attempt to use non array in fetch operator', 'non-valid-fetch', $expression['right']);
                    }
                }
                $expr = new Expression($expression['right']['right']);
                $expr->setReadOnly(true);
                $expr->setNoisy(false);
                $resolvedExpr = $expr->compile($compilationContext);
                return $compilationContext->backend->arrayIssetFetch($variable, $evalVariable, $resolvedExpr, $flags, $expression, $compilationContext);
                break;
            case 'property-access':
                $exprVariable = new Expression($expression['right']['left']);
                $exprVariable->setReadOnly(true);
                $exprVariable->setNoisy(false);
                $exprCompiledVariable = $exprVariable->compile($compilationContext);
                if ($exprCompiledVariable->getType() != 'variable') {
                    throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as object", $expression['right']['left']);
                }
                $evalVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression['right']['left']);
                if ($evalVariable->getType() != 'variable') {
                    throw new CompilerException("Variable type: " . $variable->getType() . " cannot be used as object", $expression['right']['left']);
                }
                if ($evalVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
                    $compilationContext->logger->warning('Possible attempt to use non object in fetch operator', 'non-valid-fetch', $expression['right']);
                }
                $property = $expression['right']['right']['value'];
                $compilationContext->headersManager->add('kernel/object');
                $symbol = $compilationContext->backend->getVariableCodePointer($variable);
                $evalSymbol = $compilationContext->backend->getVariableCode($evalVariable);
                return new CompiledExpression('bool', 'zephir_fetch_property(' . $symbol . ', ' . $evalSymbol . ', SL("' . $property . '"), PH_SILENT_CC)', $expression);
            case 'property-dynamic-access':
                $exprVariable = new Expression($expression['right']['left']);
                $exprVariable->setReadOnly(true);
                $exprVariable->setNoisy(false);
                $exprCompiledVariable = $exprVariable->compile($compilationContext);
                if ($exprCompiledVariable->getType() != 'variable') {
                    throw new CompilerException("Expression type: " . $exprCompiledVariable->getType() . " cannot be used as object", $expression['right']['left']);
                }
                $evalVariable = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariable->getCode(), $compilationContext, $expression['right']['left']);
                if ($evalVariable->getType() != 'variable') {
                    throw new CompilerException("Variable type: " . $evalVariable->getType() . " cannot be used as object", $expression['right']['left']);
                }
                if ($evalVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) {
                    $compilationContext->logger->warning('Possible attempt to use non object in fetch operator', 'non-valid-fetch', $expression['right']);
                }
                $exprVariableProperty = new Expression($expression['right']['right']);
                $exprVariableProperty->setReadOnly(true);
                $exprCompiledVariableProperty = $exprVariableProperty->compile($compilationContext);
                if ($exprCompiledVariableProperty->getType() != 'variable') {
                    throw new CompilerException("Expression type: " . $exprCompiledVariableProperty->getType() . " cannot be used in property-dynamic-access", $expression['right']['right']);
                }
                $evalVariableProperty = $compilationContext->symbolTable->getVariableForRead($exprCompiledVariableProperty->getCode(), $compilationContext, $expression['right']['right']);
                if ($evalVariableProperty->getType() != 'variable' && $evalVariableProperty->getType() != 'string') {
                    throw new CompilerException("Variable type: " . $evalVariableProperty->getType() . " cannot be used in property-dynamic-access", $expression['right']['right']);
                }
                $compilationContext->headersManager->add('kernel/object');
                $symbol = $compilationContext->backend->getVariableCodePointer($variable);
                $evalSymbol = $compilationContext->backend->getVariableCode($evalVariable);
                $evalPropertySymbol = $compilationContext->backend->getVariableCode($evalVariableProperty);
                return new CompiledExpression('bool', 'zephir_fetch_property_zval(' . $symbol . ', ' . $evalSymbol . ', ' . $evalPropertySymbol . ', PH_SILENT_CC)', $expression);
            default:
                throw new CompilerException('Cannot use this expression for "fetch" operators: ' . $expression['right']['type'], $expression);
        }
    }

Usage Example

Example #1
0
 /**
  * Resolves an expression
  *
  * @param CompilationContext $compilationContext
  * @return bool|CompiledExpression|mixed
  * @throws CompilerException
  */
 public function compile(CompilationContext $compilationContext)
 {
     $expression = $this->_expression;
     $type = $expression['type'];
     switch ($type) {
         case 'null':
             return new LiteralCompiledExpression('null', null, $expression);
         case 'int':
         case 'integer':
             return new LiteralCompiledExpression('int', $expression['value'], $expression);
         case 'long':
             return new LiteralCompiledExpression('long', $expression['value'], $expression);
         case 'double':
             return new LiteralCompiledExpression('double', $expression['value'], $expression);
         case 'bool':
             return new LiteralCompiledExpression('bool', $expression['value'], $expression);
         case 'string':
             if (!$this->_stringOperation) {
                 if (ctype_digit($expression['value'])) {
                     return new CompiledExpression('int', $expression['value'], $expression);
                 }
             }
             return new LiteralCompiledExpression('string', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
         case 'istring':
             return new LiteralCompiledExpression('istring', str_replace(PHP_EOL, '\\n', $expression['value']), $expression);
         case 'char':
             if (!strlen($expression['value'])) {
                 throw new CompilerException("Invalid empty char literal", $expression);
             }
             if (strlen($expression['value']) > 2) {
                 if (strlen($expression['value']) > 10) {
                     throw new CompilerException("Invalid char literal: '" . substr($expression['value'], 0, 10) . "...'", $expression);
                 } else {
                     throw new CompilerException("Invalid char literal: '" . $expression['value'] . "'", $expression);
                 }
             }
             return new LiteralCompiledExpression('char', $expression['value'], $expression);
         case 'variable':
             return new CompiledExpression('variable', $expression['value'], $expression);
         case 'constant':
             $constant = new Constants();
             $constant->setReadOnly($this->isReadOnly());
             $constant->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $constant->compile($expression, $compilationContext);
         case 'empty-array':
             return $this->emptyArray($expression, $compilationContext);
         case 'array-access':
             $arrayAccess = new NativeArrayAccess();
             $arrayAccess->setReadOnly($this->isReadOnly());
             $arrayAccess->setNoisy($this->isNoisy());
             $arrayAccess->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $arrayAccess->compile($expression, $compilationContext);
         case 'property-access':
             $propertyAccess = new PropertyAccess();
             $propertyAccess->setReadOnly($this->isReadOnly());
             $propertyAccess->setNoisy($this->isNoisy());
             $propertyAccess->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $propertyAccess->compile($expression, $compilationContext);
         case 'property-string-access':
         case 'property-dynamic-access':
             $propertyAccess = new PropertyDynamicAccess();
             $propertyAccess->setReadOnly($this->isReadOnly());
             $propertyAccess->setNoisy($this->isNoisy());
             $propertyAccess->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $propertyAccess->compile($expression, $compilationContext);
         case 'static-constant-access':
             $staticConstantAccess = new StaticConstantAccess();
             $staticConstantAccess->setReadOnly($this->isReadOnly());
             $staticConstantAccess->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $staticConstantAccess->compile($expression, $compilationContext);
         case 'static-property-access':
             $staticPropertyAccess = new StaticPropertyAccess();
             $staticPropertyAccess->setReadOnly($this->isReadOnly());
             $staticPropertyAccess->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $staticPropertyAccess->compile($expression, $compilationContext);
         case 'fcall':
             $functionCall = new FunctionCall();
             return $functionCall->compile($this, $compilationContext);
         case 'mcall':
             $methodCall = new MethodCall();
             return $methodCall->compile($this, $compilationContext);
         case 'scall':
             $staticCall = new StaticCall();
             return $staticCall->compile($this, $compilationContext);
         case 'isset':
             $expr = new IssetOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'fetch':
             $expr = new FetchOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'empty':
             $expr = new EmptyOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'array':
             $array = new NativeArray();
             $array->setReadOnly($this->isReadOnly());
             $array->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $array->compile($expression, $compilationContext);
         case 'new':
             $expr = new NewInstanceOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'new-type':
             $expr = new NewInstanceTypeOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'not':
             $expr = new NotOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'bitwise_not':
             $expr = new BitwiseNotOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'equals':
             $expr = new EqualsOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'not-equals':
             $expr = new NotEqualsOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'identical':
             $expr = new IdenticalOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'not-identical':
             $expr = new NotIdenticalOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'greater':
             $expr = new GreaterOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'less':
             $expr = new LessOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'less-equal':
             $expr = new LessEqualOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'greater-equal':
             $expr = new GreaterEqualOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'add':
             $expr = new AddOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'minus':
             $expr = new MinusOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'sub':
             $expr = new SubOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'mul':
             $expr = new MulOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'div':
             $expr = new DivOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'mod':
             $expr = new ModOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'and':
             $expr = new AndOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'or':
             $expr = new OrOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'bitwise_and':
             $expr = new BitwiseAndOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'bitwise_or':
             $expr = new BitwiseOrOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'bitwise_xor':
             $expr = new BitwiseXorOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'bitwise_shiftleft':
             $expr = new ShiftLeftOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'bitwise_shiftright':
             $expr = new ShiftRightOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'concat':
             $expr = new ConcatOperator();
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'irange':
             $expr = new RangeInclusiveOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'erange':
             $expr = new RangeExclusiveOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'list':
             if ($expression['left']['type'] == 'list') {
                 $compilationContext->logger->warning("Unnecessary extra parentheses", "extra-parentheses", $expression);
             }
             $numberPrints = $compilationContext->codePrinter->getNumberPrints();
             $expr = new Expression($expression['left']);
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             $resolved = $expr->compile($compilationContext);
             if ($compilationContext->codePrinter->getNumberPrints() - $numberPrints <= 1) {
                 if (strpos($resolved->getCode(), ' ') !== false) {
                     return new CompiledExpression($resolved->getType(), '(' . $resolved->getCode() . ')', $expression);
                 }
             }
             return $resolved;
         case 'cast':
             $expr = new CastOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'type-hint':
             return $this->compileTypeHint($expression, $compilationContext);
         case 'instanceof':
             $expr = new InstanceOfOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'clone':
             $expr = new CloneOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'ternary':
             $expr = new TernaryOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'likely':
             if (!$this->_evalMode) {
                 throw new CompilerException("'likely' operator can only be used in evaluation expressions", $expression);
             }
             $expr = new LikelyOperator();
             $expr->setReadOnly($this->isReadOnly());
             return $expr->compile($expression, $compilationContext);
         case 'unlikely':
             if (!$this->_evalMode) {
                 throw new CompilerException("'unlikely' operator can only be used in evaluation expressions", $expression);
             }
             $expr = new UnlikelyOperator();
             $expr->setReadOnly($this->isReadOnly());
             return $expr->compile($expression, $compilationContext);
         case 'typeof':
             $expr = new TypeOfOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'require':
             $expr = new RequireOperator();
             $expr->setReadOnly($this->isReadOnly());
             $expr->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $expr->compile($expression, $compilationContext);
         case 'closure':
             $closure = new Closure();
             $closure->setReadOnly($this->isReadOnly());
             $closure->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $closure->compile($expression, $compilationContext);
         case 'closure-arrow':
             $closure = new ClosureArrow();
             $closure->setReadOnly($this->isReadOnly());
             $closure->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $closure->compile($expression, $compilationContext);
         case 'reference':
             $reference = new Reference();
             $reference->setReadOnly($this->isReadOnly());
             $reference->setExpectReturn($this->_expecting, $this->_expectingVariable);
             return $reference->compile($expression, $compilationContext);
         default:
             throw new CompilerException("Unknown expression: " . $type, $expression);
     }
 }
FetchOperator