From b7915671854621ed26f8e156ffbd902d9e218fe5 Mon Sep 17 00:00:00 2001 From: Serghei Iakovlev Date: Mon, 22 Oct 2018 00:20:25 +0300 Subject: [PATCH] Fixed issue #1667 --- Library/ArgInfoDefinition.php | 38 ++++++++------ Library/ClassDefinition.php | 2 +- Library/Compiler.php | 2 +- test/typehinting/testabstract.zep | 6 +++ .../Extension/TypeHinting/AbstractTest.php | 50 +++++++++++++++++++ .../fixtures/mocks/TestConcreteClass.php | 20 ++++++++ 6 files changed, 101 insertions(+), 17 deletions(-) create mode 100644 test/typehinting/testabstract.zep create mode 100644 unit-tests/Extension/TypeHinting/AbstractTest.php create mode 100644 unit-tests/fixtures/mocks/TestConcreteClass.php diff --git a/Library/ArgInfoDefinition.php b/Library/ArgInfoDefinition.php index 74d96425a4..54e31fd994 100644 --- a/Library/ArgInfoDefinition.php +++ b/Library/ArgInfoDefinition.php @@ -38,7 +38,7 @@ class ArgInfoDefinition private $booleanDefinition = '_IS_BOOL'; /** @var bool */ - private $rightFormat = true; + private $richFormat = true; public function __construct( $name, @@ -62,9 +62,9 @@ public function setBooleanDefinition($definition) $this->booleanDefinition = (string)$definition; } - public function setRightFormat($flag) + public function setRichFormat($flag) { - $this->rightFormat = (bool)$flag; + $this->richFormat = (bool)$flag; } /** @@ -74,8 +74,8 @@ public function setRightFormat($flag) */ public function render() { - if ($this->rightFormat && $this->method->isReturnTypesHintDetermined()) { - $this->rightRenderStart(); + if ($this->richFormat && $this->method->isReturnTypesHintDetermined()) { + $this->richRenderStart(); if ($this->hasParameters() == false) { $this->codePrinter->output('ZEND_END_ARG_INFO()'); @@ -100,7 +100,7 @@ public function render() } } - private function rightRenderStart() + private function richRenderStart() { if (array_key_exists('object', $this->method->getReturnTypes())) { $class = 'NULL'; @@ -167,7 +167,7 @@ private function rightRenderStart() private function renderEnd() { - $flag = $this->rightFormat ? '1' : '0'; + $flag = $this->richFormat ? '1' : '0'; foreach ($this->parameters->getParameters() as $parameter) { switch ("{$flag}:" . $parameter['data-type']) { @@ -178,7 +178,7 @@ private function renderEnd() "\tZEND_ARG_ARRAY_INFO(%d, %s, %d)", $this->passByReference($parameter), $parameter['name'], - $this->hasDefaultValue($parameter) + (int)$this->allowNull($parameter) ) ); break; @@ -194,7 +194,7 @@ private function renderEnd() $this->passByReference($parameter), $parameter['name'], Utils::escapeClassName($this->compilationContext->getFullName($value)), - $this->hasDefaultValue($parameter) + (int)$this->allowNull($parameter) ) ); break; @@ -221,7 +221,7 @@ private function renderEnd() $this->passByReference($parameter), $parameter['name'], $this->booleanDefinition, - $this->hasDefaultValue($parameter) + (int)$this->allowNull($parameter) ) ); break; @@ -235,7 +235,7 @@ private function renderEnd() "\tZEND_ARG_TYPE_INFO(%d, %s, IS_LONG, %d)", $this->passByReference($parameter), $parameter['name'], - $this->hasDefaultValue($parameter) + (int)$this->allowNull($parameter) ) ); break; @@ -245,7 +245,7 @@ private function renderEnd() "\tZEND_ARG_TYPE_INFO(%d, %s, IS_DOUBLE, %d)", $this->passByReference($parameter), $parameter['name'], - $this->hasDefaultValue($parameter) + (int)$this->allowNull($parameter) ) ); break; @@ -256,7 +256,7 @@ private function renderEnd() "\tZEND_ARG_TYPE_INFO(%d, %s, IS_STRING, %d)", $this->passByReference($parameter), $parameter['name'], - $this->hasDefaultValue($parameter) + (int)$this->allowNull($parameter) ) ); break; @@ -278,9 +278,17 @@ private function hasParameters() return $this->parameters !== null && count($this->parameters->getParameters()) > 0; } - private function hasDefaultValue($parameter) + private function allowNull($parameter) { - return isset($parameter['default']) ? 1 : 0; + if (!isset($parameter['default']) || !is_array(isset($parameter['default']))) { + return false; + } + + if ($parameter['default']['type'] == 'null') { + return true; + } + + return false; } private function passByReference($parameter) diff --git a/Library/ClassDefinition.php b/Library/ClassDefinition.php index cea00c5140..2887600588 100644 --- a/Library/ClassDefinition.php +++ b/Library/ClassDefinition.php @@ -1251,7 +1251,7 @@ public function compile(CompilationContext $compilationContext) ); $argInfo->setBooleanDefinition($this->compiler->backend->isZE3() ? '_IS_BOOL' : 'IS_BOOL'); - $argInfo->setRightFormat($this->compiler->backend->isZE3()); + $argInfo->setRichFormat($this->compiler->backend->isZE3()); $argInfo->render(); } diff --git a/Library/Compiler.php b/Library/Compiler.php index 7eec5b006d..c873e227e7 100644 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -2107,7 +2107,7 @@ public function generateFunctionInformation() $headerPrinter->output('PHP_FUNCTION(' . $funcName . ');'); $argInfo->setBooleanDefinition($this->backend->isZE3() ? '_IS_BOOL' : 'IS_BOOL'); - $argInfo->setRightFormat($this->backend->isZE3()); + $argInfo->setRichFormat($this->backend->isZE3()); $argInfo->render(); diff --git a/test/typehinting/testabstract.zep b/test/typehinting/testabstract.zep new file mode 100644 index 0000000000..b23998a65c --- /dev/null +++ b/test/typehinting/testabstract.zep @@ -0,0 +1,6 @@ +namespace Test\TypeHinting; + +abstract class TestAbstract +{ + abstract public function testFunc(array text = [], string text2 = "", boolean flag = true, int optional = null); +} diff --git a/unit-tests/Extension/TypeHinting/AbstractTest.php b/unit-tests/Extension/TypeHinting/AbstractTest.php new file mode 100644 index 0000000000..4a59f60f61 --- /dev/null +++ b/unit-tests/Extension/TypeHinting/AbstractTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Extension\TypeHinting; + +use PHPUnit\Framework\SkippedTestError; +use TestConcreteClass; +use Zephir\Support\TestCase; + +class AbstractTest extends TestCase +{ + /** + * {@inheritdoc} + * + * @return void + */ + public static function setUpBeforeClass() + { + if (PHP_VERSION_ID < 70000) { + throw new SkippedTestError("Scalar type hint are avalibale in PHP 7 only"); + } + } + + /** + * @test + * @link https://github.com/phalcon/zephir/issues/1667 + */ + public function shouldCreateCompatibleChildClassUsingTypeHintedParams() + { + $childClass = new TestConcreteClass(); + + $this->assertEquals( + [[1667], '/', true, null], + $childClass->testFunc([1667], '/', true, null) + ); + + $this->assertEquals( + [['issue'], '\\', true, 1667], + $childClass->testFunc(['issue'], '\\', true, 1667) + ); + } +} diff --git a/unit-tests/fixtures/mocks/TestConcreteClass.php b/unit-tests/fixtures/mocks/TestConcreteClass.php new file mode 100644 index 0000000000..2f86ba1a46 --- /dev/null +++ b/unit-tests/fixtures/mocks/TestConcreteClass.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Test\TypeHinting\TestAbstract; + +class TestConcreteClass extends TestAbstract +{ + public function testFunc(array $text = [], string $text2 = '', bool $flag = true, int $optional = null) + { + return func_get_args(); + } +}