Returns whether the variable is temporal or not
public isTemporal ( ) : boolean | ||
return | boolean |
/** * Compiles foo->x = {expr} * * @param string $variable * @param ZephirVariable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->getType() != 'variable') { throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement); } $propertyName = $statement['property']; $className = $compilationContext->classDefinition->getCompleteName(); if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate static property '" . $className . "::" . $propertyName . "' because it is not initialized", $statement); } if ($symbolVariable->getType() != 'variable') { throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement); } if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object'))) { $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement); } /** * Try to check if property is implemented on related object */ if ($variable == 'this') { if (!$compilationContext->classDefinition->hasProperty($propertyName)) { throw new CompilerException("Property '" . $propertyName . "' is not defined on class '" . $className . "'", $statement); } } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/object'); switch ($resolvedExpr->getType()) { case 'null': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } break; case 'int': case 'long': case 'uint': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'mul-assign': case 'sub-assign': case 'add-assign': switch ($statement['operator']) { case 'mul-assign': $functionName = 'ZEPHIR_MUL_ASSIGN'; break; case 'sub-assign': $functionName = 'ZEPHIR_SUB_ASSIGN'; break; case 'add-assign': $functionName = 'ZEPHIR_ADD_ASSIGN'; break; } $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $resolvedVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); $codePrinter->output($functionName . '(' . $tempVariable->getName() . ', ' . $resolvedVariable->getName() . ')'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'char': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', \'' . $resolvedExpr->getBooleanCode() . '\');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'mul-assign': case 'sub-assign': case 'add-assign': switch ($statement['operator']) { case 'mul-assign': $functionName = 'ZEPHIR_MUL_ASSIGN'; break; case 'sub-assign': $functionName = 'ZEPHIR_SUB_ASSIGN'; break; case 'add-assign': $functionName = 'ZEPHIR_ADD_ASSIGN'; break; } $resolvedVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $resolvedVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); $codePrinter->output($functionName . '(' . $tempVariable->getName() . ', ' . $resolvedVariable->getName() . ')'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); break; default: throw new CompilerException("Operator '" . $statement['operator'] . "' is not supported for object property: " . $tempVariable->getType(), $statement); } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); switch ($statement['operator']) { case 'concat-assign': $codePrinter->output('zephir_concat_self_str(&' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", sizeof("' . $resolvedExpr->getCode() . '")-1 TSRMLS_CC);'); break; case 'assign': $tempVariable->initNonReferenced($compilationContext); $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); break; } if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'array': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $resolvedExpr->getCode() . ' TSRMLS_CC);'); } break; case 'bool': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), (' . $resolvedExpr->getBooleanCode() . ') ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } break; case 'empty-array': /* unreachable code */ $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext); $codePrinter->output('array_init(' . $tempVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'variable': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'double': $tempVariable = $compilationContext->symbolTable->getTempNonTrackedVariable('variable', $compilationContext, true); $codePrinter->output('ZVAL_DOUBLE(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } $tempVariable->setIdle(true); break; case 'bool': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' ? ZEPHIR_GLOBAL(global_true) : ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } break; case 'array': case 'string': case 'variable': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', SL("' . $propertyName . '"), ' . $variableVariable->getName() . ' TSRMLS_CC);'); } if ($symbolVariable->isTemporal()) { $symbolVariable->setIdle(true); } break; default: throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } }
/** * Compiles foo->{x} = {expr} * * @param string $variable * @param Variable $symbolVariable * @param CompiledExpression $resolvedExpr * @param CompilationContext $compilationContext * @param array $statement */ public function assign($variable, ZephirVariable $symbolVariable, CompiledExpression $resolvedExpr, CompilationContext $compilationContext, $statement) { if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate variable '" . $variable . "' because it is not initialized", $statement); } if ($symbolVariable->getType() != 'variable') { throw new CompilerException("Variable type '" . $symbolVariable->getType() . "' cannot be used as object", $statement); } $propertyName = $statement['property']; $propertyVariable = $compilationContext->symbolTable->getVariableForRead($propertyName, $compilationContext, $statement); if ($propertyVariable->isNotVariableAndString()) { throw new CompilerException("Cannot use variable type '" . $propertyVariable->getType() . "' to update object property", $statement); } if (!$symbolVariable->isInitialized()) { throw new CompilerException("Cannot mutate static property '" . $compilationContext->classDefinition->getCompleteName() . "::" . $propertyName . "' because it is not initialized", $statement); } if ($symbolVariable->getType() != 'variable') { throw new CompilerException("Cannot use variable type: " . $symbolVariable->getType() . " as an object", $statement); } if ($symbolVariable->hasAnyDynamicType('unknown')) { throw new CompilerException("Cannot use non-initialized variable as an object", $statement); } /** * Trying to use a non-object dynamic variable as object */ if ($symbolVariable->hasDifferentDynamicType(array('undefined', 'object', 'null'))) { $compilationContext->logger->warning('Possible attempt to update property on non-object dynamic property', 'non-valid-objectupdate', $statement); } $codePrinter = $compilationContext->codePrinter; $compilationContext->headersManager->add('kernel/object'); $propertyVariableName = $compilationContext->symbolTable->getVariable($propertyName); switch ($resolvedExpr->getType()) { case 'null': if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_null) TSRMLS_CC);'); } break; case 'int': case 'long': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $resolvedExpr->getBooleanCode() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'string': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_STRING(' . $tempVariable->getName() . ', "' . $resolvedExpr->getCode() . '", 1);'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'bool': if ($variable == 'this') { if ($resolvedExpr->getBooleanCode() == '1') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } } else { if ($resolvedExpr->getBooleanCode() == '1') { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_true) TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ZEPHIR_GLOBAL(global_false) TSRMLS_CC);'); } } break; case 'empty-array': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('array_init(' . $tempVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'variable': $variableVariable = $compilationContext->symbolTable->getVariableForRead($resolvedExpr->getCode(), $compilationContext, $statement); switch ($variableVariable->getType()) { case 'int': case 'uint': case 'long': case 'ulong': case 'char': case 'uchar': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_LONG(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); break; case 'bool': $tempVariable = $compilationContext->symbolTable->getTempVariableForWrite('variable', $compilationContext); $codePrinter->output('ZVAL_BOOL(' . $tempVariable->getName() . ', ' . $variableVariable->getName() . ');'); if ($variable == 'this') { $codePrinter->output('zephir_update_property_this(this_ptr, Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } else { $codePrinter->output('zephir_update_property_zval(' . $symbolVariable->getName() . ', Z_STRVAL_P(' . $propertyVariableName->getName() . '), Z_STRLEN_P(' . $propertyVariableName->getName() . '), ' . $tempVariable->getName() . ' TSRMLS_CC);'); } break; case 'string': case 'variable': $codePrinter->output('zephir_update_property_zval_zval(' . $symbolVariable->getName() . ', ' . $propertyVariable->getName() . ', ' . $resolvedExpr->getCode() . ' TSRMLS_CC);'); if ($symbolVariable->isTemporal()) { $symbolVariable->setIdle(true); } break; default: throw new CompilerException("Unknown type " . $variableVariable->getType(), $statement); } break; default: throw new CompilerException("Unknown type " . $resolvedExpr->getType(), $statement); } }
/** * Retrieves/Creates a function cache for a method call * * @param CompilationContext $compilationContext * @param ClassMethod $method * @param Variable $caller */ public function get(CompilationContext $compilationContext, $methodName, Variable $caller) { $compiler = $compilationContext->compiler; $numberPoly = 0; if ($caller->getRealName() == 'this') { $classDefinition = $compilationContext->classDefinition; if ($classDefinition->hasMethod($methodName)) { $numberPoly++; $method = $classDefinition->getMethod($methodName); } } else { $classTypes = $caller->getClassTypes(); foreach ($classTypes as $classType) { if ($compiler->isClass($classType) || $compiler->isInterface($classType) || $compiler->isBundledClass($classType) || $compiler->isBundledInterface($classType)) { if ($compiler->isInterface($classType)) { continue; } if ($compiler->isClass($classType)) { $classDefinition = $compiler->getClassDefinition($classType); } else { $classDefinition = $compiler->getInternalClassDefinition($classType); } if (!$classDefinition) { continue; } if ($classDefinition->hasMethod($methodName) && !$classDefinition->isInterface()) { $numberPoly++; $method = $classDefinition->getMethod($methodName); } } } } if (!$numberPoly) { // Try to generate a cache based on the fact the variable is not modified within the loop block if ($compilationContext->insideCycle && !$caller->isTemporal()) { if (count($compilationContext->cycleBlocks) && $caller->getType() == 'variable') { $currentBlock = $compilationContext->cycleBlocks[count($compilationContext->cycleBlocks) - 1]; if ($currentBlock->getMutateGatherer(true)->getNumberOfMutations($caller->getName()) == 0) { $functionCache = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext); $functionCache->setMustInitNull(true); $functionCache->setReusable(false); return '&' . $functionCache->getName() . ', 0'; } } } return 'NULL, 0'; } if (!$method instanceof \ReflectionMethod) { if ($method->getClassDefinition()->isExternal()) { return 'NULL, 0'; } $completeName = $method->getClassDefinition()->getCompleteName(); if (isset($this->cache[$completeName][$method->getName()])) { return $this->cache[$completeName][$method->getName()] . ', ' . SlotsCache::getExistingMethodSlot($method); } $gatherer = $this->gatherer; if (is_object($gatherer)) { $number = $gatherer->getNumberOfMethodCalls($method->getClassDefinition()->getCompleteName(), $method->getName()); } else { $number = 0; } $staticCacheable = !$method->getClassDefinition()->isInterface() && ($compilationContext->currentMethod == $method || $method->getClassDefinition()->isFinal() || $method->isFinal() || $method->isPrivate()); if ($number > 1 || $compilationContext->insideCycle) { $cacheable = true; } else { $cacheable = false; } } else { $staticCacheable = false; $cacheable = false; } // Recursive methods require warm-up if ($compilationContext->currentMethod == $method) { if (!$compilationContext->methodWarmUp) { $compilationContext->methodWarmUp = new MethodCallWarmUp(); } } $associatedClass = false; if ($caller->getName() != 'this_ptr') { $associatedClass = $caller->getAssociatedClass(); if ($this->isClassCacheable($associatedClass)) { $staticCacheable = true; } } if ($staticCacheable) { $cacheSlot = SlotsCache::getMethodSlot($method); } else { $cacheSlot = '0'; } if ($cacheable) { $functionCacheVar = $compilationContext->symbolTable->getTempVariableForWrite('zephir_fcall_cache_entry', $compilationContext); $functionCacheVar->setMustInitNull(true); $functionCacheVar->setReusable(false); $functionCache = '&' . $functionCacheVar->getName(); } else { $functionCache = 'NULL'; } if (!$method instanceof \ReflectionMethod) { $this->cache[$completeName][$method->getName()] = $functionCache; } return $functionCache . ', ' . $cacheSlot; }