Find this useful? Enter your email to receive occasional updates for securing PHP code.
Signing you up...
Thank you for signing up!
PHP Decode
<?php /** * This file is part of the Zephir. * * (c) Phalcon Team <[email protected]..
Decoded Output download
<?php
/**
* This file is part of the Zephir.
*
* (c) Phalcon Team <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Zephir;
use ReflectionException;
use Zephir\Class\Definition\Definition;
use Zephir\Class\Method\Method;
use Zephir\Detectors\ReadDetector;
use Zephir\Exception\CompilerException;
use Zephir\Traits\VariablesTrait;
use Zephir\Variable\Variable;
use function count;
use function implode;
use function in_array;
use function is_object;
use function is_string;
use function sprintf;
use function str_replace;
use function strtolower;
use function strtoupper;
/**
* Call methods in a static context
*/
class StaticCall extends Call
{
use VariablesTrait;
/**
* Compiles a static method call.
*
* @param Expression $expr
* @param CompilationContext $compilationContext
*
* @return CompiledExpression
*
* @throws Exception
* @throws ReflectionException
*/
public function compile(Expression $expr, CompilationContext $compilationContext): CompiledExpression
{
$expression = $expr->getExpression();
$methodName = strtolower($expression['name']);
$dynamicMethod = $expression['dynamic'] ?? false;
$symbolVariable = null;
/**
* Create temporary variable if needed.
*/
$mustInit = false;
$isExpecting = $expr->isExpectingReturn();
if ($isExpecting) {
$symbolVariable = $expr->getExpectingVariable();
if (is_object($symbolVariable)) {
$readDetector = new ReadDetector();
if ($readDetector->detect($symbolVariable->getName(), $expression)) {
$symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify(
'variable',
$compilationContext
);
} else {
$mustInit = true;
}
} else {
$symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify(
'variable',
$compilationContext
);
}
}
/**
* Method calls only return zvals, so we need to validate the target variable is also a zval
*/
if ($isExpecting) {
/**
* At this point, we don't know the exact dynamic type returned by the static method call
*/
$symbolVariable->setDynamicTypes('undefined');
$this->checkNotVariable($symbolVariable, $expression);
}
/**
* Include fcall header
*/
$compilationContext->headersManager->add('kernel/fcall');
$compiler = $compilationContext->compiler;
$dynamicClass = $expression['dynamic-class'];
if (!$dynamicClass) {
$className = $expression['class'];
$classDefinition = false;
if (!in_array($className, ['self', 'static', 'parent'])) {
if (is_string($className)) {
$className = $compilationContext->getFullName($className);
if ($compiler->isClass($className)) {
$classDefinition = $compiler->getClassDefinition($className);
} else {
if ($compiler->isBundledClass($className)) {
$classDefinition = $compiler->getInternalClassDefinition($className);
} else {
throw new CompilerException('Class name: ' . $className . ' does not exist', $expression);
}
}
} else {
foreach ($className as $singleClass) {
$className = $compilationContext->getFullName($singleClass);
if ($compiler->isClass($singleClass)) {
$classDefinition = $compiler->getClassDefinition($singleClass);
} else {
throw new CompilerException('Class name: ' . $className . ' does not exist', $expression);
}
}
}
} else {
$classDefinition = $compilationContext->classDefinition;
if ('parent' === $className) {
$extendsClass = $classDefinition->getExtendsClass();
if (!$extendsClass) {
throw new CompilerException(
'Cannot call method "'
. $methodName
. '" on parent because class '
. $classDefinition->getCompleteName()
. ' does not extend any class',
$expression
);
}
$currentClassDefinition = $classDefinition;
$classDefinition = $classDefinition->getExtendsClassDefinition();
}
}
}
/**
* Check if the class implements the method
*/
if (!$dynamicMethod && !$dynamicClass) {
// TODO: Consider to check instance of ClassDefinitionRuntime and throw another error, telling that class was not found.
// TODO: This will give false if external class does not exists!
if (!$classDefinition->hasMethod($methodName)) {
$possibleMethod = $classDefinition->getPossibleMethodName($methodName);
if ($possibleMethod) {
throw new CompilerException(
"Class '"
. $classDefinition->getCompleteName()
. "' does not implement static method: '"
. $expression['name']
. "'. Did you mean '"
. $possibleMethod
. "'?",
$expression
);
} else {
throw new CompilerException(
"Class '"
. $classDefinition->getCompleteName()
. "' does not implement static method: '"
. $expression['name']
. "'",
$expression
);
}
} else {
$method = $classDefinition->getMethod($methodName);
if ($method->isPrivate() && $method->getClassDefinition() !== $compilationContext->classDefinition) {
throw new CompilerException(
"Cannot call private method '" . $methodName . "' out of its scope",
$expression
);
}
if (!in_array($className, ['self', 'static', 'parent']) && !$method->isStatic()) {
throw new CompilerException(
"Cannot call non-static method '" . $methodName . "' in a static way",
$expression
);
}
if (!$classDefinition->hasMethod('__callStatic')) {
if ($method instanceof Method && !$method->isBundled()) {
/**
* Try to produce an exception if method is called with a wrong number of parameters
*/
$callNumberParameters = isset($expression['parameters']) ? count(
$expression['parameters']
) : 0;
$classMethod = $classDefinition->getMethod($methodName);
$expectedNumberParameters = $classMethod->getNumberOfRequiredParameters();
if (!$expectedNumberParameters && $callNumberParameters > 0) {
$numberParameters = $classMethod->getNumberOfParameters();
if ($callNumberParameters > $numberParameters) {
throw new CompilerException(
"Method '" . $classDefinition->getCompleteName() . '::' . $expression['name']
. "' called with a wrong number of parameters, the method has: "
. $expectedNumberParameters
. ', passed: '
. $callNumberParameters,
$expression
);
}
}
if ($callNumberParameters < $expectedNumberParameters) {
throw new CompilerException(
"Method '"
. $classDefinition->getCompleteName()
. '::'
. $expression['name']
. "' called with a wrong number of parameters, the method has: "
. $expectedNumberParameters
. ', passed: '
. $callNumberParameters,
$expression
);
}
}
} else {
if (!isset($method)) {
$method = $classDefinition->getMethod('__callStatic');
if (
$method->isPrivate() &&
$method->getClassDefinition() !== $compilationContext->classDefinition
) {
throw new CompilerException(
"Cannot call private magic method '__call' out of its scope",
$expression
);
}
}
}
}
}
/**
* Call static methods in the same class, use the special context 'self' or special context 'static'
* Call static methods in the 'self' context
*/
if (!$dynamicMethod) {
if ($dynamicClass) {
$this->callFromDynamicClass(
$methodName,
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$compilationContext
);
} else {
if (
in_array($className, ['self', 'static']) ||
$classDefinition == $compilationContext->classDefinition
) {
$this->call(
strtoupper($className),
$methodName,
$expression,
$mustInit,
$isExpecting,
$compilationContext,
$symbolVariable,
$method ?? null
);
} else {
if ('parent' == $className) {
$this->callParent(
$methodName,
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$currentClassDefinition,
$compilationContext,
$method ?? null
);
} else {
$this->callFromClass(
$methodName,
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$classDefinition,
$compilationContext,
$method ?? null
);
}
}
}
} else {
if ($dynamicClass) {
$this->callFromDynamicClassDynamicMethod(
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$compilationContext
);
}
}
/**
* Add the last call status to the current symbol table
*/
$this->addCallStatusFlag($compilationContext);
/**
* Transfer the return type-hint to the returned variable
*/
if ($isExpecting && isset($method) && $method instanceof Method) {
$symbolVariable->setDynamicTypes('object');
foreach ($method->getReturnClassTypes() as $classType) {
$symbolVariable->setClassTypes($compilationContext->getFullName($classType));
}
foreach ($method->getReturnTypes() as $dataType => $returnType) {
$symbolVariable->setDynamicTypes($dataType);
}
}
/**
* We can mark temporary variables generated as idle here
*/
foreach ($this->getTemporalVariables() as $tempVariable) {
$tempVariable->setIdle(true);
}
if ($isExpecting) {
return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
}
return new CompiledExpression('null', null, $expression);
}
/**
* Calls static methods on the 'self/static' context.
*
* @param string $context SELF / STATIC
* @param string $methodName
* @param array $expression
* @param bool $mustInit
* @param bool $isExpecting
* @param CompilationContext $compilationContext
* @param Variable|null $symbolVariable
* @param Method|null $method
*
* @throws Exception
*/
protected function call(
string $context,
string $methodName,
array $expression,
bool $mustInit,
bool $isExpecting,
CompilationContext $compilationContext,
Variable $symbolVariable = null,
Method $method = null
): void {
if (!in_array($context, ['SELF', 'STATIC'])) {
$context = 'SELF';
}
/**
* Do not optimize static:: calls, to allow late static binding
*/
if ('SELF' === $context) {
$method = $method->getOptimizedMethod();
}
$codePrinter = $compilationContext->codePrinter;
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
/**
* Check if the method call can have an inline cache.
*/
$methodCache = $compilationContext->cacheManager->getStaticMethodCache();
$cachePointer = $methodCache->get($compilationContext, $method ?? null);
$params = [];
if (isset($expression['parameters']) && count($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$paramCount = count($params);
$paramsStr = $paramCount ? ', ' . implode(', ', $params) : '';
$isInternal = isset($method) && $method->isInternal();
if (!$isInternal) {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_' . $context . '("' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_' . $context . '(' . $symbol . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_' . $context . '(NULL, "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
} else {
$ce = $method->getClassDefinition()->getClassEntry($compilationContext);
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 1, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 2, $paramCount);
$codePrinter->output(
$macro . '(' . $symbol . ', ' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');'
);
}
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 0, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
}
}
/**
* 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);
}
/**
* Calls static methods on some class context.
*
* @param string $methodName
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param Definition $classDefinition
* @param CompilationContext $compilationContext
* @param Method $method
*
* @throws Exception
*/
protected function callFromClass(
$methodName,
array $expression,
$symbolVariable,
$mustInit,
$isExpecting,
Definition $classDefinition,
CompilationContext $compilationContext,
Method $method
): void {
$codePrinter = $compilationContext->codePrinter;
if ($classDefinition->isBundled()) {
$classEntryVariable = $compilationContext->symbolTable->addTemp('zend_class_entry', $compilationContext);
$compilationContext->backend->fetchClass(
$classEntryVariable,
'SL("' . str_replace('\', '\\', $classDefinition->getName()) . '")',
false,
$compilationContext
);
$classEntry = $classEntryVariable->getName();
} else {
$classEntry = $classDefinition->getClassEntry($compilationContext);
}
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
$method = $method->getOptimizedMethod();
/**
* Check if the method call can have an inline cache.
*/
$methodCache = $compilationContext->cacheManager->getStaticMethodCache();
$cachePointer = $methodCache->get($compilationContext, $method);
$params = [];
if (isset($expression['parameters']) && count($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$paramCount = count($params);
$paramsStr = $paramCount ? ', ' . implode(', ', $params) : '';
if ($method->isInternal()) {
$ce = $classDefinition->getClassEntry($compilationContext);
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 1, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 2, $paramCount);
$codePrinter->output(
$macro . '(' . $symbol . ', ' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');'
);
}
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 0, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
}
} else {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(' . $symbol . ', ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
}
/**
* 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);
}
/**
* Calls static methods on using a dynamic variable as class.
*
* @param string $methodName
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param CompilationContext $compilationContext
*/
protected function callFromDynamicClass(
string $methodName,
array $expression,
$symbolVariable,
$mustInit,
$isExpecting,
CompilationContext $compilationContext
): void {
[$params, $classEntry] = $this->fetchClassParams($expression, $compilationContext, $symbolVariable, $mustInit);
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$cachePointer = 'NULL, 0';
if (!count($params)) {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(' . $symbol . ', ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(' . $symbol . ', ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
}
}
/**
* Temporary variables must be copied if they have more than one reference
*/
foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
$compilationContext->codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
}
$this->addCallStatusOrJump($compilationContext);
}
/**
* Calls static methods on using a dynamic variable as class and a dynamic method.
*
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param CompilationContext $compilationContext
*/
protected function callFromDynamicClassDynamicMethod(
array $expression,
$symbolVariable,
bool $mustInit,
bool $isExpecting,
CompilationContext $compilationContext
): void {
[$params, $classEntry] = $this->fetchClassParams($expression, $compilationContext, $symbolVariable, $mustInit);
/**
* Obtain the method name from the variable.
*/
$methodNameVariable = $compilationContext->symbolTable->getVariableForRead(
$expression['name'],
$compilationContext,
$expression
);
if ($methodNameVariable->isNotVariableAndString()) {
throw new CompilerException('Only dynamic/string variables can be used in dynamic methods', $expression);
}
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$cachePointer = 'NULL, 0';
if (!count($params)) {
if ($isExpecting) {
if ('return_value' === $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC_ZVAL(' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(' . $symbol . ', ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(NULL, ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ');'
);
}
} else {
if ($isExpecting) {
if ('return_value' === $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC_ZVAL(' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ', ' . implode(', ', $params) . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(' . $symbol . ', ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ', ' . implode(', ', $params) . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(NULL, ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ', ' . implode(', ', $params) . ');'
);
}
}
/**
* Temporary variables must be copied if they have more than one reference
*/
foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
$compilationContext->codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
}
$this->addCallStatusOrJump($compilationContext);
}
/**
* Calls static methods on the 'parent' context.
*
* @param string $methodName
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param Definition $classDefinition
* @param CompilationContext $compilationContext
* @param Method $method
*
* @throws Exception
*/
protected function callParent(
string $methodName,
array $expression,
$symbolVariable,
$mustInit,
$isExpecting,
Definition $classDefinition,
CompilationContext $compilationContext,
Method $method
): void {
$codePrinter = $compilationContext->codePrinter;
$classCe = $classDefinition->getClassEntry($compilationContext);
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
/**
* Check if the method call can have an inline cache.
*/
$methodCache = $compilationContext->cacheManager->getStaticMethodCache();
$cachePointer = $methodCache->get($compilationContext, $method ?? null);
$params = [];
if (isset($expression['parameters']) && count($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
if (!count($params)) {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_PARENT(' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(&' . $symbolVariable->getName(
) . ', ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(NULL, ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_PARENT(' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(&' . $symbolVariable->getName(
) . ', ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(NULL, ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$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 . ');');
}
$this->addCallStatusOrJump($compilationContext);
}
private function fetchClassParams(
array $expression,
CompilationContext $compilationContext,
Variable $symbolVariable,
bool $mustInit
): array {
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
$params = [];
if (!empty($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
/**
* Obtain the class entry from the variable.
*/
$classNameVariable = $compilationContext->symbolTable->getVariableForRead(
$expression['class'],
$compilationContext,
$expression
);
if ($classNameVariable->isNotVariableAndString()) {
throw new CompilerException('Only dynamic/string variables can be used in dynamic classes', $expression);
}
$compilationContext->headersManager->add('kernel/object');
$classEntryVariable = $compilationContext->symbolTable->addTemp('zend_class_entry', $compilationContext);
$compilationContext->codePrinter->output(
sprintf(
'%s = zephir_fetch_class(%s);',
$classEntryVariable->getName(),
$compilationContext->backend->getVariableCode($classNameVariable)
)
);
return [$params, $classEntryVariable->getName()];
}
}
?>
Did this file decode correctly?
Original Code
<?php
/**
* This file is part of the Zephir.
*
* (c) Phalcon Team <[email protected]>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
declare(strict_types=1);
namespace Zephir;
use ReflectionException;
use Zephir\Class\Definition\Definition;
use Zephir\Class\Method\Method;
use Zephir\Detectors\ReadDetector;
use Zephir\Exception\CompilerException;
use Zephir\Traits\VariablesTrait;
use Zephir\Variable\Variable;
use function count;
use function implode;
use function in_array;
use function is_object;
use function is_string;
use function sprintf;
use function str_replace;
use function strtolower;
use function strtoupper;
/**
* Call methods in a static context
*/
class StaticCall extends Call
{
use VariablesTrait;
/**
* Compiles a static method call.
*
* @param Expression $expr
* @param CompilationContext $compilationContext
*
* @return CompiledExpression
*
* @throws Exception
* @throws ReflectionException
*/
public function compile(Expression $expr, CompilationContext $compilationContext): CompiledExpression
{
$expression = $expr->getExpression();
$methodName = strtolower($expression['name']);
$dynamicMethod = $expression['dynamic'] ?? false;
$symbolVariable = null;
/**
* Create temporary variable if needed.
*/
$mustInit = false;
$isExpecting = $expr->isExpectingReturn();
if ($isExpecting) {
$symbolVariable = $expr->getExpectingVariable();
if (is_object($symbolVariable)) {
$readDetector = new ReadDetector();
if ($readDetector->detect($symbolVariable->getName(), $expression)) {
$symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify(
'variable',
$compilationContext
);
} else {
$mustInit = true;
}
} else {
$symbolVariable = $compilationContext->symbolTable->getTempVariableForObserveOrNullify(
'variable',
$compilationContext
);
}
}
/**
* Method calls only return zvals, so we need to validate the target variable is also a zval
*/
if ($isExpecting) {
/**
* At this point, we don't know the exact dynamic type returned by the static method call
*/
$symbolVariable->setDynamicTypes('undefined');
$this->checkNotVariable($symbolVariable, $expression);
}
/**
* Include fcall header
*/
$compilationContext->headersManager->add('kernel/fcall');
$compiler = $compilationContext->compiler;
$dynamicClass = $expression['dynamic-class'];
if (!$dynamicClass) {
$className = $expression['class'];
$classDefinition = false;
if (!in_array($className, ['self', 'static', 'parent'])) {
if (is_string($className)) {
$className = $compilationContext->getFullName($className);
if ($compiler->isClass($className)) {
$classDefinition = $compiler->getClassDefinition($className);
} else {
if ($compiler->isBundledClass($className)) {
$classDefinition = $compiler->getInternalClassDefinition($className);
} else {
throw new CompilerException('Class name: ' . $className . ' does not exist', $expression);
}
}
} else {
foreach ($className as $singleClass) {
$className = $compilationContext->getFullName($singleClass);
if ($compiler->isClass($singleClass)) {
$classDefinition = $compiler->getClassDefinition($singleClass);
} else {
throw new CompilerException('Class name: ' . $className . ' does not exist', $expression);
}
}
}
} else {
$classDefinition = $compilationContext->classDefinition;
if ('parent' === $className) {
$extendsClass = $classDefinition->getExtendsClass();
if (!$extendsClass) {
throw new CompilerException(
'Cannot call method "'
. $methodName
. '" on parent because class '
. $classDefinition->getCompleteName()
. ' does not extend any class',
$expression
);
}
$currentClassDefinition = $classDefinition;
$classDefinition = $classDefinition->getExtendsClassDefinition();
}
}
}
/**
* Check if the class implements the method
*/
if (!$dynamicMethod && !$dynamicClass) {
// TODO: Consider to check instance of ClassDefinitionRuntime and throw another error, telling that class was not found.
// TODO: This will give false if external class does not exists!
if (!$classDefinition->hasMethod($methodName)) {
$possibleMethod = $classDefinition->getPossibleMethodName($methodName);
if ($possibleMethod) {
throw new CompilerException(
"Class '"
. $classDefinition->getCompleteName()
. "' does not implement static method: '"
. $expression['name']
. "'. Did you mean '"
. $possibleMethod
. "'?",
$expression
);
} else {
throw new CompilerException(
"Class '"
. $classDefinition->getCompleteName()
. "' does not implement static method: '"
. $expression['name']
. "'",
$expression
);
}
} else {
$method = $classDefinition->getMethod($methodName);
if ($method->isPrivate() && $method->getClassDefinition() !== $compilationContext->classDefinition) {
throw new CompilerException(
"Cannot call private method '" . $methodName . "' out of its scope",
$expression
);
}
if (!in_array($className, ['self', 'static', 'parent']) && !$method->isStatic()) {
throw new CompilerException(
"Cannot call non-static method '" . $methodName . "' in a static way",
$expression
);
}
if (!$classDefinition->hasMethod('__callStatic')) {
if ($method instanceof Method && !$method->isBundled()) {
/**
* Try to produce an exception if method is called with a wrong number of parameters
*/
$callNumberParameters = isset($expression['parameters']) ? count(
$expression['parameters']
) : 0;
$classMethod = $classDefinition->getMethod($methodName);
$expectedNumberParameters = $classMethod->getNumberOfRequiredParameters();
if (!$expectedNumberParameters && $callNumberParameters > 0) {
$numberParameters = $classMethod->getNumberOfParameters();
if ($callNumberParameters > $numberParameters) {
throw new CompilerException(
"Method '" . $classDefinition->getCompleteName() . '::' . $expression['name']
. "' called with a wrong number of parameters, the method has: "
. $expectedNumberParameters
. ', passed: '
. $callNumberParameters,
$expression
);
}
}
if ($callNumberParameters < $expectedNumberParameters) {
throw new CompilerException(
"Method '"
. $classDefinition->getCompleteName()
. '::'
. $expression['name']
. "' called with a wrong number of parameters, the method has: "
. $expectedNumberParameters
. ', passed: '
. $callNumberParameters,
$expression
);
}
}
} else {
if (!isset($method)) {
$method = $classDefinition->getMethod('__callStatic');
if (
$method->isPrivate() &&
$method->getClassDefinition() !== $compilationContext->classDefinition
) {
throw new CompilerException(
"Cannot call private magic method '__call' out of its scope",
$expression
);
}
}
}
}
}
/**
* Call static methods in the same class, use the special context 'self' or special context 'static'
* Call static methods in the 'self' context
*/
if (!$dynamicMethod) {
if ($dynamicClass) {
$this->callFromDynamicClass(
$methodName,
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$compilationContext
);
} else {
if (
in_array($className, ['self', 'static']) ||
$classDefinition == $compilationContext->classDefinition
) {
$this->call(
strtoupper($className),
$methodName,
$expression,
$mustInit,
$isExpecting,
$compilationContext,
$symbolVariable,
$method ?? null
);
} else {
if ('parent' == $className) {
$this->callParent(
$methodName,
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$currentClassDefinition,
$compilationContext,
$method ?? null
);
} else {
$this->callFromClass(
$methodName,
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$classDefinition,
$compilationContext,
$method ?? null
);
}
}
}
} else {
if ($dynamicClass) {
$this->callFromDynamicClassDynamicMethod(
$expression,
$symbolVariable,
$mustInit,
$isExpecting,
$compilationContext
);
}
}
/**
* Add the last call status to the current symbol table
*/
$this->addCallStatusFlag($compilationContext);
/**
* Transfer the return type-hint to the returned variable
*/
if ($isExpecting && isset($method) && $method instanceof Method) {
$symbolVariable->setDynamicTypes('object');
foreach ($method->getReturnClassTypes() as $classType) {
$symbolVariable->setClassTypes($compilationContext->getFullName($classType));
}
foreach ($method->getReturnTypes() as $dataType => $returnType) {
$symbolVariable->setDynamicTypes($dataType);
}
}
/**
* We can mark temporary variables generated as idle here
*/
foreach ($this->getTemporalVariables() as $tempVariable) {
$tempVariable->setIdle(true);
}
if ($isExpecting) {
return new CompiledExpression('variable', $symbolVariable->getRealName(), $expression);
}
return new CompiledExpression('null', null, $expression);
}
/**
* Calls static methods on the 'self/static' context.
*
* @param string $context SELF / STATIC
* @param string $methodName
* @param array $expression
* @param bool $mustInit
* @param bool $isExpecting
* @param CompilationContext $compilationContext
* @param Variable|null $symbolVariable
* @param Method|null $method
*
* @throws Exception
*/
protected function call(
string $context,
string $methodName,
array $expression,
bool $mustInit,
bool $isExpecting,
CompilationContext $compilationContext,
Variable $symbolVariable = null,
Method $method = null
): void {
if (!in_array($context, ['SELF', 'STATIC'])) {
$context = 'SELF';
}
/**
* Do not optimize static:: calls, to allow late static binding
*/
if ('SELF' === $context) {
$method = $method->getOptimizedMethod();
}
$codePrinter = $compilationContext->codePrinter;
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
/**
* Check if the method call can have an inline cache.
*/
$methodCache = $compilationContext->cacheManager->getStaticMethodCache();
$cachePointer = $methodCache->get($compilationContext, $method ?? null);
$params = [];
if (isset($expression['parameters']) && count($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$paramCount = count($params);
$paramsStr = $paramCount ? ', ' . implode(', ', $params) : '';
$isInternal = isset($method) && $method->isInternal();
if (!$isInternal) {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_' . $context . '("' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_' . $context . '(' . $symbol . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_' . $context . '(NULL, "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
} else {
$ce = $method->getClassDefinition()->getClassEntry($compilationContext);
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 1, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 2, $paramCount);
$codePrinter->output(
$macro . '(' . $symbol . ', ' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');'
);
}
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 0, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
}
}
/**
* 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);
}
/**
* Calls static methods on some class context.
*
* @param string $methodName
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param Definition $classDefinition
* @param CompilationContext $compilationContext
* @param Method $method
*
* @throws Exception
*/
protected function callFromClass(
$methodName,
array $expression,
$symbolVariable,
$mustInit,
$isExpecting,
Definition $classDefinition,
CompilationContext $compilationContext,
Method $method
): void {
$codePrinter = $compilationContext->codePrinter;
if ($classDefinition->isBundled()) {
$classEntryVariable = $compilationContext->symbolTable->addTemp('zend_class_entry', $compilationContext);
$compilationContext->backend->fetchClass(
$classEntryVariable,
'SL("' . str_replace('\\', '\\\\', $classDefinition->getName()) . '")',
false,
$compilationContext
);
$classEntry = $classEntryVariable->getName();
} else {
$classEntry = $classDefinition->getClassEntry($compilationContext);
}
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
$method = $method->getOptimizedMethod();
/**
* Check if the method call can have an inline cache.
*/
$methodCache = $compilationContext->cacheManager->getStaticMethodCache();
$cachePointer = $methodCache->get($compilationContext, $method);
$params = [];
if (isset($expression['parameters']) && count($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$paramCount = count($params);
$paramsStr = $paramCount ? ', ' . implode(', ', $params) : '';
if ($method->isInternal()) {
$ce = $classDefinition->getClassEntry($compilationContext);
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 1, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 2, $paramCount);
$codePrinter->output(
$macro . '(' . $symbol . ', ' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');'
);
}
} else {
$macro = $compilationContext->backend->getFcallManager()->getMacro(true, 0, $paramCount);
$codePrinter->output($macro . '(' . $ce . ', ' . $method->getInternalName() . $paramsStr . ');');
}
} else {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(' . $symbol . ', ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . $paramsStr . ');'
);
}
}
/**
* 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);
}
/**
* Calls static methods on using a dynamic variable as class.
*
* @param string $methodName
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param CompilationContext $compilationContext
*/
protected function callFromDynamicClass(
string $methodName,
array $expression,
$symbolVariable,
$mustInit,
$isExpecting,
CompilationContext $compilationContext
): void {
[$params, $classEntry] = $this->fetchClassParams($expression, $compilationContext, $symbolVariable, $mustInit);
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$cachePointer = 'NULL, 0';
if (!count($params)) {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(' . $symbol . ', ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC(' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(' . $symbol . ', ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC(NULL, ' . $classEntry . ', "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
}
}
/**
* Temporary variables must be copied if they have more than one reference
*/
foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
$compilationContext->codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
}
$this->addCallStatusOrJump($compilationContext);
}
/**
* Calls static methods on using a dynamic variable as class and a dynamic method.
*
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param CompilationContext $compilationContext
*/
protected function callFromDynamicClassDynamicMethod(
array $expression,
$symbolVariable,
bool $mustInit,
bool $isExpecting,
CompilationContext $compilationContext
): void {
[$params, $classEntry] = $this->fetchClassParams($expression, $compilationContext, $symbolVariable, $mustInit);
/**
* Obtain the method name from the variable.
*/
$methodNameVariable = $compilationContext->symbolTable->getVariableForRead(
$expression['name'],
$compilationContext,
$expression
);
if ($methodNameVariable->isNotVariableAndString()) {
throw new CompilerException('Only dynamic/string variables can be used in dynamic methods', $expression);
}
if ($symbolVariable) {
$symbol = $compilationContext->backend->getVariableCode($symbolVariable);
}
$cachePointer = 'NULL, 0';
if (!count($params)) {
if ($isExpecting) {
if ('return_value' === $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC_ZVAL(' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(' . $symbol . ', ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(NULL, ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ');'
);
}
} else {
if ($isExpecting) {
if ('return_value' === $symbolVariable->getName()) {
$compilationContext->codePrinter->output(
'ZEPHIR_RETURN_CALL_CE_STATIC_ZVAL(' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ', ' . implode(', ', $params) . ');'
);
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(' . $symbol . ', ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ', ' . implode(', ', $params) . ');'
);
}
} else {
$compilationContext->codePrinter->output(
'ZEPHIR_CALL_CE_STATIC_ZVAL(NULL, ' . $classEntry . ', ' . $methodNameVariable->getName(
) . ', ' . $cachePointer . ', ' . implode(', ', $params) . ');'
);
}
}
/**
* Temporary variables must be copied if they have more than one reference
*/
foreach ($this->getMustCheckForCopyVariables() as $checkVariable) {
$compilationContext->codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');');
}
$this->addCallStatusOrJump($compilationContext);
}
/**
* Calls static methods on the 'parent' context.
*
* @param string $methodName
* @param array $expression
* @param Variable $symbolVariable
* @param bool $mustInit
* @param bool $isExpecting
* @param Definition $classDefinition
* @param CompilationContext $compilationContext
* @param Method $method
*
* @throws Exception
*/
protected function callParent(
string $methodName,
array $expression,
$symbolVariable,
$mustInit,
$isExpecting,
Definition $classDefinition,
CompilationContext $compilationContext,
Method $method
): void {
$codePrinter = $compilationContext->codePrinter;
$classCe = $classDefinition->getClassEntry($compilationContext);
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
/**
* Check if the method call can have an inline cache.
*/
$methodCache = $compilationContext->cacheManager->getStaticMethodCache();
$cachePointer = $methodCache->get($compilationContext, $method ?? null);
$params = [];
if (isset($expression['parameters']) && count($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
if (!count($params)) {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_PARENT(' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(&' . $symbolVariable->getName(
) . ', ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(NULL, ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ');'
);
}
} else {
if ($isExpecting) {
if ('return_value' == $symbolVariable->getName()) {
$codePrinter->output(
'ZEPHIR_RETURN_CALL_PARENT(' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(&' . $symbolVariable->getName(
) . ', ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$params
) . ');'
);
}
} else {
$codePrinter->output(
'ZEPHIR_CALL_PARENT(NULL, ' . $classCe . ', getThis(), "' . $methodName . '", ' . $cachePointer . ', ' . implode(
', ',
$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 . ');');
}
$this->addCallStatusOrJump($compilationContext);
}
private function fetchClassParams(
array $expression,
CompilationContext $compilationContext,
Variable $symbolVariable,
bool $mustInit
): array {
/**
* Call static methods must grow the stack
*/
$compilationContext->symbolTable->mustGrownStack(true);
if ($mustInit) {
$symbolVariable->setMustInitNull(true);
$symbolVariable->trackVariant($compilationContext);
}
$params = [];
if (!empty($expression['parameters'])) {
$params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression);
}
/**
* Obtain the class entry from the variable.
*/
$classNameVariable = $compilationContext->symbolTable->getVariableForRead(
$expression['class'],
$compilationContext,
$expression
);
if ($classNameVariable->isNotVariableAndString()) {
throw new CompilerException('Only dynamic/string variables can be used in dynamic classes', $expression);
}
$compilationContext->headersManager->add('kernel/object');
$classEntryVariable = $compilationContext->symbolTable->addTemp('zend_class_entry', $compilationContext);
$compilationContext->codePrinter->output(
sprintf(
'%s = zephir_fetch_class(%s);',
$classEntryVariable->getName(),
$compilationContext->backend->getVariableCode($classNameVariable)
)
);
return [$params, $classEntryVariable->getName()];
}
}
Function Calls
None |
Stats
MD5 | 4939dfb87cbd6544c137de1e2c261436 |
Eval Count | 0 |
Decode Time | 128 ms |