private function parseMethodParameters(ClassMethod $method) { $parameters = $method->getParameters(); if (!$parameters) { return; } foreach ($method->getParameters() as $parameter) { if (isset($parameter['data-type'])) { if ($parameter['data-type'] == 'variable') { $type = 'mixed'; } else { $type = $parameter['data-type']; } } elseif (isset($parameter['cast'])) { $type = $parameter['cast']['value']; } else { $type = 'mixed'; } $this->parameters['$' . $parameter['name']] = array($type, ''); } }
/** * @param ClassMethod $method * @param bool $isInterface * @param string $indent * * @return string */ protected function buildMethod(ClassMethod $method, $isInterface, $indent) { $modifier = implode(' ', array_diff($method->getVisibility(), $this->ignoreModifiers)); $methodParameters = $method->getParameters(); $aliasManager = $method->getClassDefinition()->getAliasManager(); $docBlock = new MethodDocBlock($method, $aliasManager, $indent); $parameters = array(); if ($methodParameters) { foreach ($methodParameters->getParameters() as $parameter) { $paramStr = ''; if (isset($parameter['cast'])) { if ($aliasManager->isAlias($parameter['cast']['value'])) { $cast = '\\' . $aliasManager->getAlias($parameter['cast']['value']); } else { $cast = $parameter['cast']['value']; } $paramStr .= $cast . ' '; } $paramStr .= '$' . $parameter['name']; if (isset($parameter['default'])) { $paramStr .= ' = ' . $this->wrapPHPValue($parameter); } $parameters[] = $paramStr; } } $methodBody = $indent . $modifier . ' function ' . $method->getName() . '(' . implode(', ', $parameters) . ')'; if ($isInterface || $method->isAbstract()) { $methodBody .= ';'; } else { $methodBody .= ' {}'; } return $docBlock . "\n" . $methodBody; }
/** * Generate internal method's based on the equivalent PHP methods, * allowing bypassing php userspace for internal method calls */ public function setupOptimized(CompilationContext $compilationContext) { if (!$compilationContext->config->get('internal-call-transformation', 'optimizations')) { return; } $classDefinition = $this->getClassDefinition(); /* Skip for closures */ if ($this->getName() == '__invoke' || $classDefinition->isInterface()) { return; } if (!$this->isInternal() && !$classDefinition->isBundled()) { /* Not supported for now */ if ($this->getNumberOfRequiredParameters() != $this->getNumberOfParameters()) { return $this; } if ($this->isConstructor()) { return $this; } $optimizedName = $this->getName() . '_zephir_internal_call'; $visibility = array('internal'); $statements = null; if ($this->statements) { $statements = new StatementsBlock(json_decode(json_encode($this->statements->getStatements()), true)); } $optimizedMethod = new ClassMethod($classDefinition, $visibility, $optimizedName, $this->parameters, $statements, $this->docblock, null, $this->expression); $optimizedMethod->typeInference = $this->typeInference; $optimizedMethod->setReturnTypes($this->returnTypes); $classDefinition->addMethod($optimizedMethod); } }
/** * Returns the signature of an internal method */ public function getInternalSignature(ClassMethod $method, CompilationContext $context) { if ($method->isInitializer() && !$method->isStatic()) { return 'static zend_object *' . $method->getName() . '(zend_class_entry *class_type TSRMLS_DC)'; } if ($method->isInitializer() && $method->isStatic()) { return 'void ' . $method->getName() . '(TSRMLS_D)'; } $signatureParameters = array(); $parameters = $method->getParameters(); if (is_object($parameters)) { foreach ($parameters->getParameters() as $parameter) { switch ($parameter['data-type']) { case 'int': case 'uint': case 'long': case 'double': case 'bool': case 'char': case 'uchar': case 'string': case 'array': $signatureParameters[] = 'zval *' . $parameter['name'] . '_param_ext'; break; default: $signatureParameters[] = 'zval *' . $parameter['name'] . '_ext '; break; } } } if (count($signatureParameters)) { return 'void ' . $method->getInternalName() . '(int ht, zval *return_value, zval *this_ptr, int return_value_used, ' . join(', ', $signatureParameters) . ')'; } return 'void ' . $method->getInternalName() . '(int ht, zval *return_value, zval *this_ptr, int return_value_used)'; }
/** * Builds a class definition from reflection * * @param \ReflectionClass $class * * @return ClassDefinition */ public static function buildFromReflection(\ReflectionClass $class) { $classDefinition = new ClassDefinition($class->getNamespaceName(), $class->getName()); $methods = $class->getMethods(); if (count($methods) > 0) { foreach ($methods as $method) { $parameters = array(); foreach ($method->getParameters() as $row) { $params = array('type' => 'parameter', 'name' => $row->getName(), 'const' => 0, 'data-type' => 'variable', 'mandatory' => !$row->isOptional()); if (!$params['mandatory']) { try { $params['default'] = $row->getDefaultValue(); } catch (\ReflectionException $e) { // TODO: dummy default value $params['default'] = true; } } $parameters[] = $params; } $classMethod = new ClassMethod($classDefinition, array(), $method->getName(), new ClassMethodParameters($parameters)); $classMethod->setIsStatic($method->isStatic()); $classMethod->setIsBundled(true); $classDefinition->addMethod($classMethod); } } $constants = $class->getConstants(); if (count($constants) > 0) { foreach ($constants as $constantName => $constantValue) { $type = self::_convertPhpConstantType(gettype($constantValue)); $classConstant = new ClassConstant($constantName, array('value' => $constantValue, 'type' => $type), null); $classDefinition->addConstant($classConstant); } } $properties = $class->getProperties(); if (count($properties) > 0) { foreach ($properties as $property) { $visibility = array(); if ($property->isPublic()) { $visibility[] = 'public'; } if ($property->isPrivate()) { $visibility[] = 'private'; } if ($property->isProtected()) { $visibility[] = 'protected'; } if ($property->isStatic()) { $visibility[] = 'static'; } $classProperty = new ClassProperty($classDefinition, $visibility, $property->getName(), null, null, null); $classDefinition->addProperty($classProperty); } } $classDefinition->setIsBundled(true); return $classDefinition; }
/** * Calls static methods on the 'self/static' context * * @param string $context SELF / STATIC * @param string $methodName * @param array $expression * @param Variable $symbolVariable * @param boolean $mustInit * @param boolean $isExpecting * @param ClassDefinition $classDefinition * @param CompilationContext $compilationContext * @param ClassMethod $method */ protected function call($context, $methodName, array $expression, $symbolVariable, $mustInit, $isExpecting, ClassDefinition $classDefinition, CompilationContext $compilationContext, ClassMethod $method) { if (!in_array($context, array('SELF', 'STATIC'))) { $context = 'SELF'; } $codePrinter = $compilationContext->codePrinter; /** * Call static methods must grown 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, isset($method) ? $method : null, false); if (isset($expression['parameters']) && count($expression['parameters'])) { $params = $this->getResolvedParams($expression['parameters'], $compilationContext, $expression); } else { $params = array(); } $isInternal = false; if (isset($method)) { $isInternal = $method->isInternal(); } if (!$isInternal) { if (!count($params)) { if ($isExpecting) { if ($symbolVariable->getName() == 'return_value') { $codePrinter->output('ZEPHIR_RETURN_CALL_' . $context . '("' . $methodName . '", ' . $cachePointer . ');'); } else { $codePrinter->output('ZEPHIR_CALL_' . $context . '(&' . $symbolVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ');'); } } else { $codePrinter->output('ZEPHIR_CALL_' . $context . '(NULL, "' . $methodName . '", ' . $cachePointer . ');'); } } else { if ($isExpecting) { if ($symbolVariable->getName() == 'return_value') { $codePrinter->output('ZEPHIR_RETURN_CALL_' . $context . '("' . $methodName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');'); } else { $codePrinter->output('ZEPHIR_CALL_' . $context . '(&' . $symbolVariable->getName() . ', "' . $methodName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');'); } } else { $codePrinter->output('ZEPHIR_CALL_' . $context . '(NULL, "' . $methodName . '", ' . $cachePointer . ', ' . join(', ', $params) . ');'); } } } else { if (!count($params)) { if ($isExpecting) { if ($symbolVariable->getName() == 'return_value') { $codePrinter->output('ZEPHIR_RETURN_CALL_INTERNAL_METHOD_P0(EG(This), ' . $method->getInternalName() . ');'); } else { $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_P0(&' . $symbolVariable->getName() . ', EG(This), ' . $method->getInternalName() . ');'); } } else { $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_NORETURN_P0(EG(This), ' . $method->getInternalName() . ');'); } } else { if ($isExpecting) { if ($symbolVariable->getName() == 'return_value') { $codePrinter->output('ZEPHIR_RETURN_CALL_INTERNAL_METHOD_P' . count($params) . '(EG(This), ' . $method->getInternalName() . ', ' . join(', ', $params) . ');'); } else { $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_P' . count($params) . '(&' . $symbolVariable->getName() . ', EG(This), ' . $method->getInternalName() . ', ' . join(', ', $params) . ');'); } } else { $codePrinter->output('ZEPHIR_CALL_INTERNAL_METHOD_NORETURN_P' . count($params) . '(EG(This), ' . $method->getInternalName() . ', ' . join(', ', $params) . ');'); } } } /** * Temporary variables must be copied if they have more than one reference */ foreach ($this->getMustCheckForCopyVariables() as $checkVariable) { $codePrinter->output('zephir_check_temp_parameter(' . $checkVariable . ');'); } $this->addCallStatusOrJump($compilationContext); }
/** * @param ClassMethod $method * * @param bool $isInterface * * @return string */ protected function buildMethod(ClassMethod $method, $isInterface) { $modifier = implode(' ', array_diff($method->getVisibility(), $this->ignoreModifiers)); $docBlock = new MethodDocBlock($method, 4); $parameters = array(); $methodParameters = $method->getParameters(); if ($methodParameters) { foreach ($methodParameters->getParameters() as $parameter) { $paramStr = '$' . $parameter['name']; if (isset($parameter['default'])) { $paramStr .= ' = ' . $this->wrapPHPValue($parameter); } $parameters[] = $paramStr; } } $methodBody = "\t" . $modifier . ' function ' . $method->getName() . '(' . implode(', ', $parameters) . ')'; if ($isInterface || $method->isAbstract()) { $methodBody .= ';'; } else { $methodBody .= ' {}'; } return $docBlock . "\n" . $methodBody; }