From e4f92f940919762a613a37e2adfaacce22618e75 Mon Sep 17 00:00:00 2001 From: Daniel Hunsaker Date: Sun, 3 Jun 2018 20:02:45 -0600 Subject: [PATCH] Add type hints for scalar arguments and return values in Zend3 Fixes #1656 --- Library/ClassDefinition.php | 112 +++++++- Library/Compiler.php | 132 ++++++++- Library/Stubs/Generator.php | 59 +++- bootstrap.php | 4 + test/oo/oonativeimplements.zep | 4 +- test/scalldynamic.zep | 10 +- unit-tests/Extension/MCallTest.php | 20 +- .../Extension/Oo/OoParamsStrictTest.php | 143 ++++++++++ unit-tests/Extension/Oo/OoParamsTest.php | 83 ------ unit-tests/Zephir/Test/LifeCycleTest.php | 2 +- unit-tests/Zephir/Test/TypeHintsTest.php | 114 ++++++++ .../Zephir/Test/_files/typehints/config.json | 46 ++++ .../Zephir/Test/_files/typehints/expected2.c | 233 ++++++++++++++++ .../Zephir/Test/_files/typehints/expected3.c | 256 ++++++++++++++++++ .../Test/_files/typehints/expected_args2.h | 21 ++ .../Test/_files/typehints/expected_args3.h | 21 ++ .../Test/_files/typehints/expected_both2.h | 15 + .../Test/_files/typehints/expected_both3.h | 19 ++ .../Test/_files/typehints/expected_retval2.h | 23 ++ .../Test/_files/typehints/expected_retval3.h | 65 +++++ .../Test/_files/typehints/typehints/args.zep | 21 ++ .../Test/_files/typehints/typehints/both.zep | 11 + .../_files/typehints/typehints/retval.zep | 75 +++++ 23 files changed, 1367 insertions(+), 122 deletions(-) create mode 100644 unit-tests/Extension/Oo/OoParamsStrictTest.php create mode 100644 unit-tests/Zephir/Test/TypeHintsTest.php create mode 100644 unit-tests/Zephir/Test/_files/typehints/config.json create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected2.c create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected3.c create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected_args2.h create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected_args3.h create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected_both2.h create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected_both3.h create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected_retval2.h create mode 100644 unit-tests/Zephir/Test/_files/typehints/expected_retval3.h create mode 100644 unit-tests/Zephir/Test/_files/typehints/typehints/args.zep create mode 100644 unit-tests/Zephir/Test/_files/typehints/typehints/both.zep create mode 100644 unit-tests/Zephir/Test/_files/typehints/typehints/retval.zep diff --git a/Library/ClassDefinition.php b/Library/ClassDefinition.php index dad9bafe78..ab1da40922 100644 --- a/Library/ClassDefinition.php +++ b/Library/ClassDefinition.php @@ -1294,32 +1294,120 @@ public function compile(CompilationContext $compilationContext) */ foreach ($methods as $method) { $parameters = $method->getParameters(); - if ($method->hasParameters()) { - $codePrinter->output('ZEND_BEGIN_ARG_INFO_EX(arginfo_' . strtolower($this->getCNamespace() . '_' . $this->getName() . '_' . $method->getName()) . ', 0, 0, ' . $method->getNumberOfRequiredParameters() . ')'); + $argInfoName = 'arginfo_' . strtolower($this->getCNamespace() . '_' . $this->getName() . '_' . $method->getName()); + + if ($this->compiler->backend->isZE3() && $method->hasReturnTypes()) { + if (array_key_exists('object', $method->getReturnTypes())) { + $class = 'NULL'; + + if (count($method->getReturnClassTypes()) == 1) { + $class = Utils::escapeClassName($compilationContext->getFullName(key($method->getReturnClassTypes()))); + } + + $codePrinter->output('#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX'); + $codePrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(' . $argInfoName . ', 0, ' . + $method->getNumberOfRequiredParameters() . ', ' . + $class . ', ' . ($method->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $codePrinter->output('#else'); + $codePrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(' . $argInfoName . ', 0, ' . + $method->getNumberOfRequiredParameters() . ', ' . + 'NULL, "' . $class . '", ' . ($method->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $codePrinter->output('#endif'); + } else { + $type = 'IS_NULL'; + + if ($method->areReturnTypesIntCompatible()) { + $type = 'IS_LONG'; + } + if ($method->areReturnTypesDoubleCompatible()) { + $type = 'IS_DOUBLE'; + } + if ($method->areReturnTypesBoolCompatible()) { + $type = '_IS_BOOL'; + } + if ($method->areReturnTypesStringCompatible()) { + $type = 'IS_STRING'; + } + + $codePrinter->output('#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX'); + $codePrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(' . $argInfoName . ', 0, ' . + $method->getNumberOfRequiredParameters() . ', ' . + $type . ', ' . ($method->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $codePrinter->output('#else'); + $codePrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(' . $argInfoName . ', 0, ' . + $method->getNumberOfRequiredParameters() . ', ' . + $type . ', NULL, ' . ($method->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $codePrinter->output('#endif'); + } + + if ($parameters == null || !count($parameters->getParameters())) { + $codePrinter->output('ZEND_END_ARG_INFO()'); + $codePrinter->outputBlankLine(); + } + } elseif ($parameters != null && count($parameters->getParameters())) { + $codePrinter->output( + 'ZEND_BEGIN_ARG_INFO_EX(' . $argInfoName . ', 0, 0, ' . + $method->getNumberOfRequiredParameters() . ')' + ); + } + + if ($parameters != null && count($parameters->getParameters())) { foreach ($parameters->getParameters() as $parameter) { - switch ($parameter['data-type']) { - case 'array': - $codePrinter->output("\t" . 'ZEND_ARG_ARRAY_INFO(0, ' . $parameter['name'] . ', ' . (isset($parameter['default']) ? 1 : 0) . ')'); + switch (($this->compiler->backend->isZE3() ? '3:' : '2:') . $parameter['data-type']) { + case '2:array': + case '3:array': + $codePrinter->output("\t" . 'ZEND_ARG_ARRAY_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ', ' . (isset($parameter['default']) ? 1 : 0) . ')'); break; - case 'variable': + case '2:variable': + case '3:variable': if (isset($parameter['cast'])) { switch ($parameter['cast']['type']) { case 'variable': $value = $parameter['cast']['value']; - $codePrinter->output("\t" . 'ZEND_ARG_OBJ_INFO(0, ' . $parameter['name'] . ', ' . Utils::escapeClassName($compilationContext->getFullName($value)) . ', ' . (isset($parameter['default']) ? 1 : 0) . ')'); + $codePrinter->output("\t" . 'ZEND_ARG_OBJ_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ', ' . Utils::escapeClassName($compilationContext->getFullName($value)) . ', ' . (isset($parameter['default']) ? 1 : 0) . ')'); break; default: throw new Exception('Unexpected exception'); } } else { - $codePrinter->output("\t" . 'ZEND_ARG_INFO(0, ' . $parameter['name'] . ')'); + $codePrinter->output("\t" . 'ZEND_ARG_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ')'); } break; + case '3:bool': + case '3:boolean': + $codePrinter->output("\t" . 'ZEND_ARG_TYPE_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ', ' . ($this->compiler->backend->isZE3() ? '_IS_BOOL' : 'IS_BOOL') . ', ' . (isset($parameter['default']) ? 1 : 0) . ')'); + break; + + case '3:uchar': + case '3:int': + case '3:uint': + case '3:long': + case '3:ulong': + $codePrinter->output("\t" . 'ZEND_ARG_TYPE_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ', IS_LONG, ' . (isset($parameter['default']) ? 1 : 0) . ')'); + break; + + case '3:double': + $codePrinter->output("\t" . 'ZEND_ARG_TYPE_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ', IS_DOUBLE, ' . (isset($parameter['default']) ? 1 : 0) . ')'); + break; + + case '3:char': + case '3:string': + $codePrinter->output("\t" . 'ZEND_ARG_TYPE_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ', IS_STRING, ' . (isset($parameter['default']) ? 1 : 0) . ')'); + break; + default: - $codePrinter->output("\t" . 'ZEND_ARG_INFO(0, ' . $parameter['name'] . ')'); + $codePrinter->output("\t" . 'ZEND_ARG_INFO(' . (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ')'); break; } } @@ -1333,7 +1421,7 @@ public function compile(CompilationContext $compilationContext) foreach ($methods as $method) { if ($this->getType() == 'class') { if (!$method->isInternal()) { - if ($method->hasParameters()) { + if (($this->compiler->backend->isZE3() && $method->hasReturnTypes()) || $method->hasParameters()) { $codePrinter->output("\t" . 'PHP_ME(' . $this->getCNamespace() . '_' . $this->getName() . ', ' . $method->getName() . ', arginfo_' . strtolower($this->getCNamespace() . '_' . $this->getName() . '_' . $method->getName()) . ', ' . $method->getModifiers() . ')'); } else { $codePrinter->output("\t" . 'PHP_ME(' . $this->getCNamespace() . '_' . $this->getName() . ', ' . $method->getName() . ', NULL, ' . $method->getModifiers() . ')'); @@ -1341,13 +1429,13 @@ public function compile(CompilationContext $compilationContext) } } else { if ($method->isStatic()) { - if ($method->hasParameters()) { + if (($this->compiler->backend->isZE3() && $method->hasReturnTypes()) || $method->hasParameters()) { $codePrinter->output("\t" . 'ZEND_FENTRY(' . $method->getName() . ', NULL, arginfo_' . strtolower($this->getCNamespace() . '_' . $this->getName() . '_' . $method->getName()) . ', ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT|ZEND_ACC_PUBLIC)'); } else { $codePrinter->output("\t" . 'ZEND_FENTRY(' . $method->getName() . ', NULL, NULL, ZEND_ACC_STATIC|ZEND_ACC_ABSTRACT|ZEND_ACC_PUBLIC)'); } } else { - if ($method->hasParameters()) { + if (($this->compiler->backend->isZE3() && $method->hasReturnTypes()) || $method->hasParameters()) { $codePrinter->output("\t" . 'PHP_ABSTRACT_ME(' . $this->getCNamespace() . '_' . $this->getName() . ', ' . $method->getName() . ', arginfo_' . strtolower($this->getCNamespace() . '_' . $this->getName() . '_' . $method->getName()) . ')'); } else { $codePrinter->output("\t" . 'PHP_ABSTRACT_ME(' . $this->getCNamespace() . '_' . $this->getName() . ', ' . $method->getName() . ', NULL)'); diff --git a/Library/Compiler.php b/Library/Compiler.php index ae4ee7e7e1..07ea0f4a08 100644 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -884,7 +884,7 @@ public function generate(CommandInterface $command) if (!$file->isDir()) { $extension = str_replace('.php', '', $file); if (!extension_loaded($extension)) { - require $file->getRealPath(); + require_once $file->getRealPath(); } } } @@ -2101,22 +2101,86 @@ public function generateFunctionInformation() $headerPrinter->output('PHP_FUNCTION(' . $funcName . ');'); $parameters = $func->getParameters(); - if ($parameters != null && count($parameters->getParameters())) { + + if ($this->backend->isZE3() && $func->hasReturnTypes()) { + if (array_key_exists('object', $func->getReturnTypes())) { + $class = 'NULL'; + + if (count($func->getReturnClassTypes()) == 1) { + $compilationContext = $func->getCallGathererPass()->getCompilationContext(); + $class = Utils::escapeClassName($compilationContext->getFullName(key($func->getReturnClassTypes()))); + } + + $headerPrinter->output('#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX'); + $headerPrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(' . $argInfoName . ', 0, ' . + $func->getNumberOfRequiredParameters() . ', ' . + $class . ', ' . ($func->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $headerPrinter->output('#else'); + $headerPrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(' . $argInfoName . ', 0, ' . + $func->getNumberOfRequiredParameters() . ', ' . + 'NULL, "' . $class . '", ' . ($func->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $headerPrinter->output('#endif'); + } else { + $type = 'IS_NULL'; + + if ($func->areReturnTypesIntCompatible()) { + $type = 'IS_LONG'; + } + if ($func->areReturnTypesDoubleCompatible()) { + $type = 'IS_DOUBLE'; + } + if ($func->areReturnTypesBoolCompatible()) { + $type = '_IS_BOOL'; + } + if ($func->areReturnTypesStringCompatible()) { + $type = 'IS_STRING'; + } + + $headerPrinter->output('#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX'); + $headerPrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(' . $argInfoName . ', 0, ' . + $func->getNumberOfRequiredParameters() . ', ' . + $type . ', ' . ($func->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $headerPrinter->output('#else'); + $headerPrinter->output( + 'ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(' . $argInfoName . ', 0, ' . + $func->getNumberOfRequiredParameters() . ', ' . + $type . ', NULL, ' . ($func->areReturnTypesNullCompatible() ? 1 : 0) . ')' + ); + $headerPrinter->output('#endif'); + } + + if ($parameters == null || !count($parameters->getParameters())) { + $headerPrinter->output('ZEND_END_ARG_INFO()'); + $headerPrinter->outputBlankLine(); + } + } elseif ($parameters != null && count($parameters->getParameters())) { $headerPrinter->output( 'ZEND_BEGIN_ARG_INFO_EX(' . $argInfoName . ', 0, 0, ' . $func->getNumberOfRequiredParameters() . ')' ); + } + if ($parameters != null && count($parameters->getParameters())) { foreach ($parameters->getParameters() as $parameter) { - switch ($parameter['data-type']) { - case 'array': + switch (($this->backend->isZE3() ? '3:' : '2:') . $parameter['data-type']) { + case '2:array': + case '3:array': $headerPrinter->output( - "\t" . 'ZEND_ARG_ARRAY_INFO(0, ' . $parameter['name'] . ', ' . + "\t" . 'ZEND_ARG_ARRAY_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . + $parameter['name'] . ', ' . (isset($parameter['default']) ? 1 : 0) . ')' ); break; - case 'variable': + case '2:variable': + case '3:variable': if (isset($parameter['cast'])) { switch ($parameter['cast']['type']) { case 'variable': @@ -2124,7 +2188,8 @@ public function generateFunctionInformation() $value = $parameter['cast']['value']; $headerPrinter->output( - "\t" . 'ZEND_ARG_OBJ_INFO(0, ' . + "\t" . 'ZEND_ARG_OBJ_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . $parameter['name'] . ', ' . Utils::escapeClassName($compilationContext->getFullName($value)) . ', ' . (isset($parameter['default']) ? 1 : 0) . ')' @@ -2135,12 +2200,59 @@ public function generateFunctionInformation() throw new Exception('Unexpected exception'); } } else { - $headerPrinter->output("\t" . 'ZEND_ARG_INFO(0, ' . $parameter['name'] . ')'); + $headerPrinter->output("\t" . 'ZEND_ARG_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . + $parameter['name'] . ')'); } break; + case '3:bool': + case '3:boolean': + $headerPrinter->output( + "\t" . 'ZEND_ARG_TYPE_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . + $parameter['name'] . ', ' . + ($this->backend->isZE3() ? '_IS_BOOL' : 'IS_BOOL') . ', ' . + (isset($parameter['default']) ? 1 : 0) . ')' + ); + break; + + case '3:uchar': + case '3:int': + case '3:uint': + case '3:long': + case '3:ulong': + $headerPrinter->output( + "\t" . 'ZEND_ARG_TYPE_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . + $parameter['name'] . ', IS_LONG, ' . + (isset($parameter['default']) ? 1 : 0) . ')' + ); + break; + + case '3:double': + $headerPrinter->output( + "\t" . 'ZEND_ARG_TYPE_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . + $parameter['name'] . ', IS_DOUBLE, ' . + (isset($parameter['default']) ? 1 : 0) . ')' + ); + break; + + case '3:char': + case '3:string': + $headerPrinter->output( + "\t" . 'ZEND_ARG_TYPE_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . + $parameter['name'] . ', IS_STRING, ' . + (isset($parameter['default']) ? 1 : 0) . ')' + ); + break; + default: - $headerPrinter->output("\t" . 'ZEND_ARG_INFO(0, ' . $parameter['name'] . ')'); + $headerPrinter->output("\t" . 'ZEND_ARG_INFO(' . + (isset($parameter['reference']) ? $parameter['reference'] : 0) . ', ' . + $parameter['name'] . ')'); break; } } @@ -2148,7 +2260,7 @@ public function generateFunctionInformation() $headerPrinter->outputBlankLine(); } /** Generate FE's */ - $paramData = (count($parameters) ? $argInfoName : 'NULL'); + $paramData = ((($this->backend->isZE3() && $func->hasReturnTypes()) || $func->hasParameters()) ? $argInfoName : 'NULL'); if ($func->isGlobal()) { $entryPrinter->output( diff --git a/Library/Stubs/Generator.php b/Library/Stubs/Generator.php index bf8facbdeb..53398c7d33 100644 --- a/Library/Stubs/Generator.php +++ b/Library/Stubs/Generator.php @@ -127,12 +127,12 @@ protected function buildClass(ClassDefinition $class, $indent) throw new \RuntimeException('Class "' . $class->getName() . '" does not have a extendsClassDefinition'); } - $source .= ' extends ' . ($extendsClassDefinition->isBundled() ? '' : '\\') . $extendsClassDefinition->getCompleteName(); + $source .= ' extends ' . ($extendsClassDefinition->isBundled() ? '' : '\\') . trim($extendsClassDefinition->getCompleteName(), '\\'); } if ($implementedInterfaces = $class->getImplementedInterfaces()) { $interfaces = array_map(function ($val) { - return '\\' . $val; + return '\\' . trim($val, '\\'); }, $implementedInterfaces); $keyword = $class->getType() == 'interface' ? ' extends ' : ' implements '; @@ -241,6 +241,16 @@ protected function buildMethod(ClassMethod $method, $isInterface, $indent) $paramStr .= $cast . ' '; } elseif (isset($parameter['data-type']) && $parameter['data-type'] == 'array') { $paramStr .= 'array '; + } elseif (isset($parameter['data-type']) && version_compare(PHP_VERSION, '7.0.0', '>=')) { + if (in_array($parameter['data-type'], ['bool', 'boolean'])) { + $paramStr .= 'bool '; + } elseif ($parameter['data-type'] == 'double') { + $paramStr .= 'float '; + } elseif (in_array($parameter['data-type'], ['int', 'uint', 'long', 'ulong', 'uchar'])) { + $paramStr .= 'int '; + } elseif (in_array($parameter['data-type'], ['char', 'string'])) { + $paramStr .= 'string '; + } } $paramStr .= '$' . $parameter['name']; @@ -253,8 +263,51 @@ protected function buildMethod(ClassMethod $method, $isInterface, $indent) } } + $return = ''; + if (version_compare(PHP_VERSION, '7.0.0', '>=') && $method->hasReturnTypes()) { + $supported = 0; + + if (array_key_exists('object', $method->getReturnTypes()) && count($method->getReturnClassTypes()) == 1) { + $return = key($method->getReturnClassTypes()); + $supported++; + } + + if ($method->areReturnTypesIntCompatible()) { + $return = 'int'; + $supported++; + } + if ($method->areReturnTypesDoubleCompatible()) { + $return = 'float'; + $supported++; + } + if ($method->areReturnTypesBoolCompatible()) { + $return = 'bool'; + $supported++; + } + if ($method->areReturnTypesStringCompatible()) { + $return = 'string'; + $supported++; + } + + if ($method->areReturnTypesNullCompatible()) { + if (version_compare(PHP_VERSION, '7.1.0', '>=')) { + $return = '?' . $return; + } else { + $return = ''; + } + } + + // PHP doesn't support multiple return types (yet?) + if ($supported > 1) { + $return = ''; + } + } + if (!empty($return)) { + $return = ': ' . $return; + } + $function = trim($modifier . ' function', ' ') . ' '; - $methodBody = $indent . $function . $method->getName() . '(' . implode(', ', $parameters) . ')'; + $methodBody = $indent . $function . $method->getName() . '(' . implode(', ', $parameters) . ')' . $return; if ($isInterface || $method->isAbstract()) { $methodBody .= ';'; diff --git a/bootstrap.php b/bootstrap.php index 18e93d5217..d916d993eb 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -37,3 +37,7 @@ require ZEPHIRPATH . 'Library/Loader.php'; Zephir\Loader::register(); } + +function unlink_recursive($path) { + exec(sprintf((PHP_OS === 'Windows') ? "rd /s /q %s" : "rm -rf %s", escapeshellarg($path))); +} diff --git a/test/oo/oonativeimplements.zep b/test/oo/oonativeimplements.zep index a2f91235f4..ee13f508b3 100644 --- a/test/oo/oonativeimplements.zep +++ b/test/oo/oonativeimplements.zep @@ -59,7 +59,7 @@ class OoNativeImplements implements /* SeekableIterator */ - public function seek (int position) + public function seek (position) { } @@ -93,4 +93,4 @@ class OoNativeImplements implements public function unserialize(string serialized) { } -} \ No newline at end of file +} diff --git a/test/scalldynamic.zep b/test/scalldynamic.zep index 490614071d..38cf90ba74 100644 --- a/test/scalldynamic.zep +++ b/test/scalldynamic.zep @@ -7,23 +7,23 @@ namespace Test; class ScallDynamic extends ScallParent { - static public function testMethod1() + static public function testMethod1() -> string { return "hello public"; } - static protected function testMethod2() + static protected function testMethod2() -> string { return "hello protected"; } - static private function testMethod3() + static private function testMethod3() -> string { return "hello private"; } - static public function selfDynamicCall1(var methodName) + static public function selfDynamicCall1(var methodName) -> string { - //return self::{methodName}(); + return self::{methodName}(); } } diff --git a/unit-tests/Extension/MCallTest.php b/unit-tests/Extension/MCallTest.php index aebca0020d..b054ab875f 100644 --- a/unit-tests/Extension/MCallTest.php +++ b/unit-tests/Extension/MCallTest.php @@ -1,4 +1,4 @@ -setExpectedException('\InvalidArgumentException'); - } else { - $this->expectException('\InvalidArgumentException'); + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + $except = '\InvalidArgumentException'; + } elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) { + $except = '\TypeError'; + } + + if (isset($except)) { + if (!method_exists('PHPUnit_Runner_Version', 'id') || + version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { + $this->setExpectedException($except); + } else { + $this->expectException($except); + } } $t->optionalParameterBoolean('test'); diff --git a/unit-tests/Extension/Oo/OoParamsStrictTest.php b/unit-tests/Extension/Oo/OoParamsStrictTest.php new file mode 100644 index 0000000000..805afc8855 --- /dev/null +++ b/unit-tests/Extension/Oo/OoParamsStrictTest.php @@ -0,0 +1,143 @@ +assertSame($t->setStrictAge(17), 17); + } + + public function testSetStrictAgeException1() + { + $t = new \Test\Oo\OoParams(); + + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + $except = '\InvalidArgumentException'; + } elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) { + $except = '\TypeError'; + } + + if (isset($except)) { + if (!method_exists('PHPUnit_Runner_Version', 'id') || + version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { + $this->setExpectedException($except); + } else { + $this->expectException($except); + } + } + + $t->setStrictAge(17.0); + } + + public function testSetStrictAgeException2() + { + $t = new \Test\Oo\OoParams(); + + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + $except = '\InvalidArgumentException'; + } elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) { + $except = '\TypeError'; + } + + if (isset($except)) { + if (!method_exists('PHPUnit_Runner_Version', 'id') || + version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { + $this->setExpectedException($except); + } else { + $this->expectException($except); + } + } + + $t->setStrictAge('17'); + } + + public function testSetStrictAverageSuccess() + { + $t = new \Test\Oo\OoParams(); + + $this->assertSame($t->setStrictAverage(17.1), 17.1); + } + + public function testSetStrictAverageException1() + { + $t = new \Test\Oo\OoParams(); + + // PHP 7 strictness coerces INT types to DOUBLE without complaint + // This is the only exception to PHP's strictness rules + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + if (!method_exists('PHPUnit_Runner_Version', 'id') || + version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { + $this->setExpectedException('\InvalidArgumentException'); + } else { + $this->expectException('\InvalidArgumentException'); + } + } + + $t->setStrictAverage(17); + } + + public function testSetStrictAverageException2() + { + $t = new \Test\Oo\OoParams(); + + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + $except = '\InvalidArgumentException'; + } elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) { + $except = '\TypeError'; + } + + if (isset($except)) { + if (!method_exists('PHPUnit_Runner_Version', 'id') || + version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { + $this->setExpectedException($except); + } else { + $this->expectException($except); + } + } + + $t->setStrictAverage('17'); + } + + public function testSetStrictNameSuccess() + { + $t = new \Test\Oo\OoParams(); + $this->assertSame($t->setStrictName('peter'), 'peter'); + } + + public function testSetStrictNameException() + { + $t = new \Test\Oo\OoParams(); + + if (version_compare(PHP_VERSION, '7.0.0', '<')) { + $except = '\InvalidArgumentException'; + } elseif (version_compare(PHP_VERSION, '7.2.0', '>=')) { + $except = '\TypeError'; + } + + if (isset($except)) { + if (!method_exists('PHPUnit_Runner_Version', 'id') || + version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { + $this->setExpectedException($except); + } else { + $this->expectException($except); + } + } + + $t->setStrictName(1234); + } +} diff --git a/unit-tests/Extension/Oo/OoParamsTest.php b/unit-tests/Extension/Oo/OoParamsTest.php index 97c2695119..9d67de9e7f 100644 --- a/unit-tests/Extension/Oo/OoParamsTest.php +++ b/unit-tests/Extension/Oo/OoParamsTest.php @@ -45,89 +45,6 @@ public function testOoParams() $this->assertSame($t->setList(array()), array()); } - public function testSetStrictAgeException1() - { - $t = new \Test\Oo\OoParams(); - - if (!method_exists('PHPUnit_Runner_Version', 'id') || - version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { - $this->setExpectedException('\InvalidArgumentException'); - } else { - $this->expectException('\InvalidArgumentException'); - } - - $t->setStrictAge(17.0); - } - - public function testSetStrictAgeException2() - { - $t = new \Test\Oo\OoParams(); - - if (!method_exists('PHPUnit_Runner_Version', 'id') || - version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { - $this->setExpectedException('\InvalidArgumentException'); - } else { - $this->expectException('\InvalidArgumentException'); - } - - $t->setStrictAge('17'); - } - - public function testSetStrictAgeSuccess() - { - $t = new \Test\Oo\OoParams(); - - $this->assertSame($t->setStrictAverage(17.1), 17.1); - } - - public function testSetStrictAverageException1() - { - $t = new \Test\Oo\OoParams(); - - if (!method_exists('PHPUnit_Runner_Version', 'id') || - version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { - $this->setExpectedException('\InvalidArgumentException'); - } else { - $this->expectException('\InvalidArgumentException'); - } - - $t->setStrictAverage(17); - } - - public function testSetStrictAverageException2() - { - $t = new \Test\Oo\OoParams(); - - if (!method_exists('PHPUnit_Runner_Version', 'id') || - version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { - $this->setExpectedException('\InvalidArgumentException'); - } else { - $this->expectException('\InvalidArgumentException'); - } - - $t->setStrictAverage('17'); - } - - public function testSetStrictNameSuccess() - { - $t = new \Test\Oo\OoParams(); - $this->assertSame($t->setStrictName('peter'), 'peter'); - } - - public function testSetStrickNameException() - { - $t = new \Test\Oo\OoParams(); - - if (!method_exists('PHPUnit_Runner_Version', 'id') || - version_compare(\PHPUnit_Runner_Version::id(), '5.2.0', '<')) { - $this->setExpectedException('\InvalidArgumentException'); - } else { - $this->expectException('\InvalidArgumentException'); - } - - $t->setStrictName(1234); - } - public function setObjectClassCast() { $t = new \Test\Oo\OoParams(); diff --git a/unit-tests/Zephir/Test/LifeCycleTest.php b/unit-tests/Zephir/Test/LifeCycleTest.php index e656e2a791..48fef9cad5 100644 --- a/unit-tests/Zephir/Test/LifeCycleTest.php +++ b/unit-tests/Zephir/Test/LifeCycleTest.php @@ -74,7 +74,7 @@ public function testLifeCycleInjectionZend3() public function tearDown() { if (file_exists('ext')) { - exec('rm -rf ext/'); + unlink_recursive('ext/'); } if (getcwd() != $this->pwd) { diff --git a/unit-tests/Zephir/Test/TypeHintsTest.php b/unit-tests/Zephir/Test/TypeHintsTest.php new file mode 100644 index 0000000000..6855c02765 --- /dev/null +++ b/unit-tests/Zephir/Test/TypeHintsTest.php @@ -0,0 +1,114 @@ +pwd = getcwd(); + } + + public function testTypeHintsZend2() + { + chdir(__DIR__ . DIRECTORY_SEPARATOR . '_files/typehints'); + $config = new Config(); + $logger = new Logger($config); + $backend = new Zend2($config); + $parser = new ParserManager(new Parser(), $logger); + $compiler = new Compiler($config, $logger, $backend, $parser); + $command = new CommandGenerate(new CommandsManager); + $compiler->generate($command); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints.c', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected2.c', FILE_IGNORE_NEW_LINES)) + ); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints/args.zep.h', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected_args2.h', FILE_IGNORE_NEW_LINES)) + ); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints/retval.zep.h', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected_retval2.h', FILE_IGNORE_NEW_LINES)) + ); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints/both.zep.h', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected_both2.h', FILE_IGNORE_NEW_LINES)) + ); + } + + public function testTypeHintsZend3() + { + chdir(__DIR__ . DIRECTORY_SEPARATOR . '_files/typehints'); + $config = new Config(); + $logger = new Logger($config); + $backend = new Zend3($config); + $parser = new ParserManager(new Parser(), $logger); + $compiler = new Compiler($config, $logger, $backend, $parser); + $command = new CommandGenerate(new CommandsManager); + $compiler->generate($command); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints.c', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected3.c', FILE_IGNORE_NEW_LINES)) + ); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints/args.zep.h', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected_args3.h', FILE_IGNORE_NEW_LINES)) + ); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints/retval.zep.h', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected_retval3.h', FILE_IGNORE_NEW_LINES)) + ); + $this->assertSame( + implode(PHP_EOL, file('ext/typehints/both.zep.h', FILE_IGNORE_NEW_LINES)), + implode(PHP_EOL, file('expected_both3.h', FILE_IGNORE_NEW_LINES)) + ); + } + + /** + * Restore current directory, and clean config.json. + */ + public function tearDown() + { + if (file_exists('.temp')) { + unlink_recursive('.temp/'); + } + + if (file_exists('ext')) { + unlink_recursive('ext/'); + } + + if (getcwd() != $this->pwd) { + chdir($this->pwd); + } + } +} diff --git a/unit-tests/Zephir/Test/_files/typehints/config.json b/unit-tests/Zephir/Test/_files/typehints/config.json new file mode 100644 index 0000000000..9ce05eaa07 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/config.json @@ -0,0 +1,46 @@ +{ + "warnings": { + "unused-variable": true, + "unused-variable-external": false, + "possible-wrong-parameter": true, + "possible-wrong-parameter-undefined": false, + "nonexistent-function": true, + "nonexistent-class": true, + "non-valid-isset": true, + "non-array-update": true, + "non-valid-objectupdate": true, + "non-valid-fetch": true, + "invalid-array-index": true, + "non-array-append": true, + "invalid-return-type": true, + "unreachable-code": true, + "nonexistent-constant": true, + "not-supported-magic-constant": true, + "non-valid-decrement": true, + "non-valid-increment": true, + "non-valid-clone": true, + "non-valid-new": true, + "non-array-access": true, + "invalid-reference": true, + "invalid-typeof-comparison": true, + "conditional-initialization": true + }, + "optimizations": { + "static-type-inference": true, + "static-type-inference-second-pass": true, + "local-context-pass": true, + "constant-folding": true, + "static-constant-class-folding": true, + "call-gatherer-pass": true, + "check-invalid-reads": false, + "private-internal-methods": false, + "public-internal-methods": false, + "public-internal-functions": true + }, + "namespace": "typehints", + "name": "TypeHints Test Extension", + "description": "Description test forTypeHints Test Extension", + "author": "Zephir Team", + "version": "1.0.0", + "verbose": true +} diff --git a/unit-tests/Zephir/Test/_files/typehints/expected2.c b/unit-tests/Zephir/Test/_files/typehints/expected2.c new file mode 100644 index 0000000000..71865a282a --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected2.c @@ -0,0 +1,233 @@ + +/* This file was generated automatically by Zephir do not modify it! */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +// TODO: Deprecated. Will be removed in future +#if PHP_VERSION_ID < 50500 +#include +#endif + +#include "php_ext.h" +#include "typehints.h" + +#include + +#include +#include +#include + +#include "kernel/globals.h" +#include "kernel/main.h" +#include "kernel/fcall.h" +#include "kernel/memory.h" + + + +zend_class_entry *typehints_args_ce; +zend_class_entry *typehints_both_ce; +zend_class_entry *typehints_retval_ce; + +ZEND_DECLARE_MODULE_GLOBALS(typehints) + +PHP_INI_BEGIN() + +PHP_INI_END() + +static PHP_MINIT_FUNCTION(typehints) +{ +// TODO: Deprecated. Will be removed in future +#if PHP_VERSION_ID < 50500 + char* old_lc_all = setlocale(LC_ALL, NULL); + if (old_lc_all) { + size_t len = strlen(old_lc_all); + char *tmp = calloc(len+1, 1); + if (UNEXPECTED(!tmp)) { + return FAILURE; + } + + memcpy(tmp, old_lc_all, len); + old_lc_all = tmp; + } + + setlocale(LC_ALL, "C"); +#endif + REGISTER_INI_ENTRIES(); + ZEPHIR_INIT(TypeHints_Args); + ZEPHIR_INIT(TypeHints_Both); + ZEPHIR_INIT(TypeHints_RetVal); + + +// TODO: Deprecated. Will be removed in future +#if PHP_VERSION_ID < 50500 + setlocale(LC_ALL, old_lc_all); + free(old_lc_all); +#endif + return SUCCESS; +} + +#ifndef ZEPHIR_RELEASE +static PHP_MSHUTDOWN_FUNCTION(typehints) +{ + + zephir_deinitialize_memory(TSRMLS_C); + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} +#endif + +/** + * Initialize globals on each request or each thread started + */ +static void php_zephir_init_globals(zend_typehints_globals *typehints_globals TSRMLS_DC) +{ + typehints_globals->initialized = 0; + + /* Memory options */ + typehints_globals->active_memory = NULL; + + /* Virtual Symbol Tables */ + typehints_globals->active_symbol_table = NULL; + + /* Cache Enabled */ + typehints_globals->cache_enabled = 1; + + /* Recursive Lock */ + typehints_globals->recursive_lock = 0; + + /* Static cache */ + memset(typehints_globals->scache, '\0', sizeof(zephir_fcall_cache_entry*) * ZEPHIR_MAX_CACHE_SLOTS); + + + +} + +/** + * Initialize globals only on each thread started + */ +static void php_zephir_init_module_globals(zend_typehints_globals *typehints_globals TSRMLS_DC) +{ + +} + +static PHP_RINIT_FUNCTION(typehints) +{ + zend_typehints_globals *typehints_globals_ptr = ZEPHIR_VGLOBAL; + + php_zephir_init_globals(typehints_globals_ptr TSRMLS_CC); + //zephir_init_interned_strings(TSRMLS_C); + zephir_initialize_memory(typehints_globals_ptr TSRMLS_CC); + + + return SUCCESS; +} + +static PHP_RSHUTDOWN_FUNCTION(typehints) +{ + + zephir_deinitialize_memory(TSRMLS_C); + return SUCCESS; +} + + + +static PHP_MINFO_FUNCTION(typehints) +{ + php_info_print_box_start(0); + php_printf("%s", PHP_TYPEHINTS_DESCRIPTION); + php_info_print_box_end(); + + php_info_print_table_start(); + php_info_print_table_header(2, PHP_TYPEHINTS_NAME, "enabled"); + php_info_print_table_row(2, "Author", PHP_TYPEHINTS_AUTHOR); + php_info_print_table_row(2, "Version", PHP_TYPEHINTS_VERSION); + php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__ ); + php_info_print_table_row(2, "Powered by Zephir", "Version " PHP_TYPEHINTS_ZEPVERSION); + php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); +} + +static PHP_GINIT_FUNCTION(typehints) +{ + php_zephir_init_globals(typehints_globals TSRMLS_CC); + php_zephir_init_module_globals(typehints_globals TSRMLS_CC); +} + +static PHP_GSHUTDOWN_FUNCTION(typehints) +{ + +} + +PHP_FUNCTION(f_TypeHints_args); +ZEND_BEGIN_ARG_INFO_EX(arginfo_f_typehints_args, 0, 0, 7) + ZEND_ARG_INFO(0, _var) + ZEND_ARG_INFO(0, _string) + ZEND_ARG_INFO(0, _bool) + ZEND_ARG_INFO(0, _int) + ZEND_ARG_INFO(0, _long) + ZEND_ARG_INFO(0, _double) + ZEND_ARG_OBJ_INFO(0, _args, TypeHints\\Args, 0) +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_both); +ZEND_BEGIN_ARG_INFO_EX(arginfo_f_typehints_both, 0, 0, 1) + ZEND_ARG_INFO(0, _string) +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_retval_var); +PHP_FUNCTION(f_TypeHints_retval_string); +PHP_FUNCTION(f_TypeHints_retval_boolean); +PHP_FUNCTION(f_TypeHints_retval_int); +PHP_FUNCTION(f_TypeHints_retval_long); +PHP_FUNCTION(f_TypeHints_retval_double); +PHP_FUNCTION(f_TypeHints_retval_retval); + +zend_function_entry php_typehints_functions[] = { + ZEND_NS_NAMED_FE("TypeHints", args, ZEND_FN(f_TypeHints_args), arginfo_f_typehints_args) +ZEND_NS_NAMED_FE("TypeHints", both, ZEND_FN(f_TypeHints_both), arginfo_f_typehints_both) +ZEND_NS_NAMED_FE("TypeHints", retval_var, ZEND_FN(f_TypeHints_retval_var), NULL) +ZEND_NS_NAMED_FE("TypeHints", retval_string, ZEND_FN(f_TypeHints_retval_string), NULL) +ZEND_NS_NAMED_FE("TypeHints", retval_boolean, ZEND_FN(f_TypeHints_retval_boolean), NULL) +ZEND_NS_NAMED_FE("TypeHints", retval_int, ZEND_FN(f_TypeHints_retval_int), NULL) +ZEND_NS_NAMED_FE("TypeHints", retval_long, ZEND_FN(f_TypeHints_retval_long), NULL) +ZEND_NS_NAMED_FE("TypeHints", retval_double, ZEND_FN(f_TypeHints_retval_double), NULL) +ZEND_NS_NAMED_FE("TypeHints", retval_retval, ZEND_FN(f_TypeHints_retval_retval), NULL) +ZEND_FE_END + +}; + +zend_module_entry typehints_module_entry = { + STANDARD_MODULE_HEADER_EX, + NULL, + NULL, + PHP_TYPEHINTS_EXTNAME, + php_typehints_functions, + PHP_MINIT(typehints), +#ifndef ZEPHIR_RELEASE + PHP_MSHUTDOWN(typehints), +#else + NULL, +#endif + PHP_RINIT(typehints), + PHP_RSHUTDOWN(typehints), + PHP_MINFO(typehints), + PHP_TYPEHINTS_VERSION, + ZEND_MODULE_GLOBALS(typehints), + PHP_GINIT(typehints), + PHP_GSHUTDOWN(typehints), +#ifdef ZEPHIR_POST_REQUEST + PHP_PRSHUTDOWN(typehints), +#else + NULL, +#endif + STANDARD_MODULE_PROPERTIES_EX +}; + +#ifdef COMPILE_DL_TYPEHINTS +ZEND_GET_MODULE(typehints) +#endif diff --git a/unit-tests/Zephir/Test/_files/typehints/expected3.c b/unit-tests/Zephir/Test/_files/typehints/expected3.c new file mode 100644 index 0000000000..22bc87d0ec --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected3.c @@ -0,0 +1,256 @@ + +/* This file was generated automatically by Zephir do not modify it! */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "php_ext.h" +#include "typehints.h" + +#include + +#include +#include +#include + +#include "kernel/globals.h" +#include "kernel/main.h" +#include "kernel/fcall.h" +#include "kernel/memory.h" + + + +zend_class_entry *typehints_args_ce; +zend_class_entry *typehints_both_ce; +zend_class_entry *typehints_retval_ce; + +ZEND_DECLARE_MODULE_GLOBALS(typehints) + +PHP_INI_BEGIN() + +PHP_INI_END() + +static PHP_MINIT_FUNCTION(typehints) +{ + REGISTER_INI_ENTRIES(); + zephir_module_init(); + ZEPHIR_INIT(TypeHints_Args); + ZEPHIR_INIT(TypeHints_Both); + ZEPHIR_INIT(TypeHints_RetVal); + + return SUCCESS; +} + +#ifndef ZEPHIR_RELEASE +static PHP_MSHUTDOWN_FUNCTION(typehints) +{ + + zephir_deinitialize_memory(TSRMLS_C); + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} +#endif + +/** + * Initialize globals on each request or each thread started + */ +static void php_zephir_init_globals(zend_typehints_globals *typehints_globals TSRMLS_DC) +{ + typehints_globals->initialized = 0; + + /* Memory options */ + typehints_globals->active_memory = NULL; + + /* Virtual Symbol Tables */ + typehints_globals->active_symbol_table = NULL; + + /* Cache Enabled */ + typehints_globals->cache_enabled = 1; + + /* Recursive Lock */ + typehints_globals->recursive_lock = 0; + + /* Static cache */ + memset(typehints_globals->scache, '\0', sizeof(zephir_fcall_cache_entry*) * ZEPHIR_MAX_CACHE_SLOTS); + + + +} + +/** + * Initialize globals only on each thread started + */ +static void php_zephir_init_module_globals(zend_typehints_globals *typehints_globals TSRMLS_DC) +{ + +} + +static PHP_RINIT_FUNCTION(typehints) +{ + zend_typehints_globals *typehints_globals_ptr; +#ifdef ZTS + tsrm_ls = ts_resource(0); +#endif + typehints_globals_ptr = ZEPHIR_VGLOBAL; + + php_zephir_init_globals(typehints_globals_ptr TSRMLS_CC); + zephir_initialize_memory(typehints_globals_ptr TSRMLS_CC); + + + return SUCCESS; +} + +static PHP_RSHUTDOWN_FUNCTION(typehints) +{ + + zephir_deinitialize_memory(TSRMLS_C); + return SUCCESS; +} + + + +static PHP_MINFO_FUNCTION(typehints) +{ + php_info_print_box_start(0); + php_printf("%s", PHP_TYPEHINTS_DESCRIPTION); + php_info_print_box_end(); + + php_info_print_table_start(); + php_info_print_table_header(2, PHP_TYPEHINTS_NAME, "enabled"); + php_info_print_table_row(2, "Author", PHP_TYPEHINTS_AUTHOR); + php_info_print_table_row(2, "Version", PHP_TYPEHINTS_VERSION); + php_info_print_table_row(2, "Build Date", __DATE__ " " __TIME__ ); + php_info_print_table_row(2, "Powered by Zephir", "Version " PHP_TYPEHINTS_ZEPVERSION); + php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); +} + +static PHP_GINIT_FUNCTION(typehints) +{ + php_zephir_init_globals(typehints_globals TSRMLS_CC); + php_zephir_init_module_globals(typehints_globals TSRMLS_CC); +} + +static PHP_GSHUTDOWN_FUNCTION(typehints) +{ + +} + +PHP_FUNCTION(f_TypeHints_args); +ZEND_BEGIN_ARG_INFO_EX(arginfo_f_typehints_args, 0, 0, 7) + ZEND_ARG_INFO(0, _var) + ZEND_ARG_TYPE_INFO(0, _string, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, _bool, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, _int, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, _long, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, _double, IS_DOUBLE, 0) + ZEND_ARG_OBJ_INFO(0, _args, TypeHints\\Args, 0) +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_both); +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_both, 0, 1, IS_STRING, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_both, 0, 1, IS_STRING, NULL, 0) +#endif + ZEND_ARG_TYPE_INFO(0, _string, IS_STRING, 0) +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_retval_var); +PHP_FUNCTION(f_TypeHints_retval_string); +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_string, 0, 0, IS_STRING, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_string, 0, 0, IS_STRING, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_retval_boolean); +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_boolean, 0, 0, _IS_BOOL, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_boolean, 0, 0, _IS_BOOL, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_retval_int); +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_int, 0, 0, IS_LONG, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_int, 0, 0, IS_LONG, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_retval_long); +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_long, 0, 0, IS_LONG, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_long, 0, 0, IS_LONG, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_retval_double); +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_double, 0, 0, IS_DOUBLE, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_double, 0, 0, IS_DOUBLE, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +PHP_FUNCTION(f_TypeHints_retval_retval); +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_f_typehints_retval_retval, 0, 0, TypeHints\\RetVal, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_f_typehints_retval_retval, 0, 0, NULL, "TypeHints\\RetVal", 0) +#endif +ZEND_END_ARG_INFO() + + +zend_function_entry php_typehints_functions[] = { + ZEND_NS_NAMED_FE("TypeHints", args, ZEND_FN(f_TypeHints_args), arginfo_f_typehints_args) +ZEND_NS_NAMED_FE("TypeHints", both, ZEND_FN(f_TypeHints_both), arginfo_f_typehints_both) +ZEND_NS_NAMED_FE("TypeHints", retval_var, ZEND_FN(f_TypeHints_retval_var), NULL) +ZEND_NS_NAMED_FE("TypeHints", retval_string, ZEND_FN(f_TypeHints_retval_string), arginfo_f_typehints_retval_string) +ZEND_NS_NAMED_FE("TypeHints", retval_boolean, ZEND_FN(f_TypeHints_retval_boolean), arginfo_f_typehints_retval_boolean) +ZEND_NS_NAMED_FE("TypeHints", retval_int, ZEND_FN(f_TypeHints_retval_int), arginfo_f_typehints_retval_int) +ZEND_NS_NAMED_FE("TypeHints", retval_long, ZEND_FN(f_TypeHints_retval_long), arginfo_f_typehints_retval_long) +ZEND_NS_NAMED_FE("TypeHints", retval_double, ZEND_FN(f_TypeHints_retval_double), arginfo_f_typehints_retval_double) +ZEND_NS_NAMED_FE("TypeHints", retval_retval, ZEND_FN(f_TypeHints_retval_retval), arginfo_f_typehints_retval_retval) +ZEND_FE_END + +}; + +zend_module_entry typehints_module_entry = { + STANDARD_MODULE_HEADER_EX, + NULL, + NULL, + PHP_TYPEHINTS_EXTNAME, + php_typehints_functions, + PHP_MINIT(typehints), +#ifndef ZEPHIR_RELEASE + PHP_MSHUTDOWN(typehints), +#else + NULL, +#endif + PHP_RINIT(typehints), + PHP_RSHUTDOWN(typehints), + PHP_MINFO(typehints), + PHP_TYPEHINTS_VERSION, + ZEND_MODULE_GLOBALS(typehints), + PHP_GINIT(typehints), + PHP_GSHUTDOWN(typehints), +#ifdef ZEPHIR_POST_REQUEST + PHP_PRSHUTDOWN(typehints), +#else + NULL, +#endif + STANDARD_MODULE_PROPERTIES_EX +}; + +#ifdef COMPILE_DL_TYPEHINTS +ZEND_GET_MODULE(typehints) +#endif diff --git a/unit-tests/Zephir/Test/_files/typehints/expected_args2.h b/unit-tests/Zephir/Test/_files/typehints/expected_args2.h new file mode 100644 index 0000000000..e936c74ab6 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected_args2.h @@ -0,0 +1,21 @@ + +extern zend_class_entry *typehints_args_ce; + +ZEPHIR_INIT_CLASS(TypeHints_Args); + +PHP_METHOD(TypeHints_Args, args); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_typehints_args_args, 0, 0, 7) + ZEND_ARG_INFO(0, _var) + ZEND_ARG_INFO(0, _string) + ZEND_ARG_INFO(0, _bool) + ZEND_ARG_INFO(0, _int) + ZEND_ARG_INFO(0, _long) + ZEND_ARG_INFO(0, _double) + ZEND_ARG_OBJ_INFO(0, _args, TypeHints\\Args, 0) +ZEND_END_ARG_INFO() + +ZEPHIR_INIT_FUNCS(typehints_args_method_entry) { + PHP_ME(TypeHints_Args, args, arginfo_typehints_args_args, ZEND_ACC_PUBLIC) + PHP_FE_END +}; diff --git a/unit-tests/Zephir/Test/_files/typehints/expected_args3.h b/unit-tests/Zephir/Test/_files/typehints/expected_args3.h new file mode 100644 index 0000000000..37317ef871 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected_args3.h @@ -0,0 +1,21 @@ + +extern zend_class_entry *typehints_args_ce; + +ZEPHIR_INIT_CLASS(TypeHints_Args); + +PHP_METHOD(TypeHints_Args, args); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_typehints_args_args, 0, 0, 7) + ZEND_ARG_INFO(0, _var) + ZEND_ARG_TYPE_INFO(0, _string, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, _bool, _IS_BOOL, 0) + ZEND_ARG_TYPE_INFO(0, _int, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, _long, IS_LONG, 0) + ZEND_ARG_TYPE_INFO(0, _double, IS_DOUBLE, 0) + ZEND_ARG_OBJ_INFO(0, _args, TypeHints\\Args, 0) +ZEND_END_ARG_INFO() + +ZEPHIR_INIT_FUNCS(typehints_args_method_entry) { + PHP_ME(TypeHints_Args, args, arginfo_typehints_args_args, ZEND_ACC_PUBLIC) + PHP_FE_END +}; diff --git a/unit-tests/Zephir/Test/_files/typehints/expected_both2.h b/unit-tests/Zephir/Test/_files/typehints/expected_both2.h new file mode 100644 index 0000000000..8560db5523 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected_both2.h @@ -0,0 +1,15 @@ + +extern zend_class_entry *typehints_both_ce; + +ZEPHIR_INIT_CLASS(TypeHints_Both); + +PHP_METHOD(TypeHints_Both, both); + +ZEND_BEGIN_ARG_INFO_EX(arginfo_typehints_both_both, 0, 0, 1) + ZEND_ARG_INFO(0, _string) +ZEND_END_ARG_INFO() + +ZEPHIR_INIT_FUNCS(typehints_both_method_entry) { + PHP_ME(TypeHints_Both, both, arginfo_typehints_both_both, ZEND_ACC_PUBLIC) + PHP_FE_END +}; diff --git a/unit-tests/Zephir/Test/_files/typehints/expected_both3.h b/unit-tests/Zephir/Test/_files/typehints/expected_both3.h new file mode 100644 index 0000000000..f4d9e0b859 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected_both3.h @@ -0,0 +1,19 @@ + +extern zend_class_entry *typehints_both_ce; + +ZEPHIR_INIT_CLASS(TypeHints_Both); + +PHP_METHOD(TypeHints_Both, both); + +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_both_both, 0, 1, IS_STRING, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_both_both, 0, 1, IS_STRING, NULL, 0) +#endif + ZEND_ARG_TYPE_INFO(0, _string, IS_STRING, 0) +ZEND_END_ARG_INFO() + +ZEPHIR_INIT_FUNCS(typehints_both_method_entry) { + PHP_ME(TypeHints_Both, both, arginfo_typehints_both_both, ZEND_ACC_PUBLIC) + PHP_FE_END +}; diff --git a/unit-tests/Zephir/Test/_files/typehints/expected_retval2.h b/unit-tests/Zephir/Test/_files/typehints/expected_retval2.h new file mode 100644 index 0000000000..ce12f39fb0 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected_retval2.h @@ -0,0 +1,23 @@ + +extern zend_class_entry *typehints_retval_ce; + +ZEPHIR_INIT_CLASS(TypeHints_RetVal); + +PHP_METHOD(TypeHints_RetVal, retval_var); +PHP_METHOD(TypeHints_RetVal, retval_string); +PHP_METHOD(TypeHints_RetVal, retval_boolean); +PHP_METHOD(TypeHints_RetVal, retval_int); +PHP_METHOD(TypeHints_RetVal, retval_long); +PHP_METHOD(TypeHints_RetVal, retval_double); +PHP_METHOD(TypeHints_RetVal, retval_retval); + +ZEPHIR_INIT_FUNCS(typehints_retval_method_entry) { + PHP_ME(TypeHints_RetVal, retval_var, NULL, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_string, NULL, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_boolean, NULL, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_int, NULL, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_long, NULL, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_double, NULL, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_retval, NULL, ZEND_ACC_PUBLIC) + PHP_FE_END +}; diff --git a/unit-tests/Zephir/Test/_files/typehints/expected_retval3.h b/unit-tests/Zephir/Test/_files/typehints/expected_retval3.h new file mode 100644 index 0000000000..692c110057 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/expected_retval3.h @@ -0,0 +1,65 @@ + +extern zend_class_entry *typehints_retval_ce; + +ZEPHIR_INIT_CLASS(TypeHints_RetVal); + +PHP_METHOD(TypeHints_RetVal, retval_var); +PHP_METHOD(TypeHints_RetVal, retval_string); +PHP_METHOD(TypeHints_RetVal, retval_boolean); +PHP_METHOD(TypeHints_RetVal, retval_int); +PHP_METHOD(TypeHints_RetVal, retval_long); +PHP_METHOD(TypeHints_RetVal, retval_double); +PHP_METHOD(TypeHints_RetVal, retval_retval); + +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_string, 0, 0, IS_STRING, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_string, 0, 0, IS_STRING, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_boolean, 0, 0, _IS_BOOL, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_boolean, 0, 0, _IS_BOOL, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_int, 0, 0, IS_LONG, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_int, 0, 0, IS_LONG, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_long, 0, 0, IS_LONG, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_long, 0, 0, IS_LONG, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_double, 0, 0, IS_DOUBLE, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_double, 0, 0, IS_DOUBLE, NULL, 0) +#endif +ZEND_END_ARG_INFO() + +#ifdef ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_typehints_retval_retval_retval, 0, 0, TypeHints\\RetVal, 0) +#else +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_typehints_retval_retval_retval, 0, 0, NULL, "TypeHints\\RetVal", 0) +#endif +ZEND_END_ARG_INFO() + +ZEPHIR_INIT_FUNCS(typehints_retval_method_entry) { + PHP_ME(TypeHints_RetVal, retval_var, NULL, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_string, arginfo_typehints_retval_retval_string, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_boolean, arginfo_typehints_retval_retval_boolean, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_int, arginfo_typehints_retval_retval_int, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_long, arginfo_typehints_retval_retval_long, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_double, arginfo_typehints_retval_retval_double, ZEND_ACC_PUBLIC) + PHP_ME(TypeHints_RetVal, retval_retval, arginfo_typehints_retval_retval_retval, ZEND_ACC_PUBLIC) + PHP_FE_END +}; diff --git a/unit-tests/Zephir/Test/_files/typehints/typehints/args.zep b/unit-tests/Zephir/Test/_files/typehints/typehints/args.zep new file mode 100644 index 0000000000..c9d39c788c --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/typehints/args.zep @@ -0,0 +1,21 @@ +namespace TypeHints; + +class Args { + public function args(_var, string _string, boolean _bool, int _int, long _long, double _double, _args) { + echo _var; + echo _string; + echo _bool; + echo _long; + echo _double; + echo _args; + } +} + +function args(_var, string _string, boolean _bool, int _int, long _long, double _double, _args) { + echo _var; + echo _string; + echo _bool; + echo _long; + echo _double; + echo _args; +} diff --git a/unit-tests/Zephir/Test/_files/typehints/typehints/both.zep b/unit-tests/Zephir/Test/_files/typehints/typehints/both.zep new file mode 100644 index 0000000000..aaefbf97ff --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/typehints/both.zep @@ -0,0 +1,11 @@ +namespace TypeHints; + +class Both { + public function both(string _string) -> string { + return _string; + } +} + +function both(string _string) -> string { + return _string; +} diff --git a/unit-tests/Zephir/Test/_files/typehints/typehints/retval.zep b/unit-tests/Zephir/Test/_files/typehints/typehints/retval.zep new file mode 100644 index 0000000000..1449173de8 --- /dev/null +++ b/unit-tests/Zephir/Test/_files/typehints/typehints/retval.zep @@ -0,0 +1,75 @@ +namespace TypeHints; + +class RetVal { + public function retval_var() { + var _var; + return _var; + } + + public function retval_string() -> string { + string _var; + return _var; + } + + public function retval_boolean() -> boolean { + boolean _var; + return _var; + } + + public function retval_int() -> int { + int _var; + return _var; + } + + public function retval_long() -> long { + long _var; + return _var; + } + + public function retval_double() -> double { + double _var; + return _var; + } + + public function retval_retval() -> { + var _var; + let _var = new RetVal; + return _var; + } +} + +function retval_var() { + var _var; + return _var; +} + +function retval_string() -> string { + string _var; + return _var; +} + +function retval_boolean() -> boolean { + boolean _var; + return _var; +} + +function retval_int() -> int { + int _var; + return _var; +} + +function retval_long() -> long { + long _var; + return _var; +} + +function retval_double() -> double { + double _var; + return _var; +} + +function retval_retval() -> { + var _var; + let _var = new RetVal; + return _var; +}