From 8694ed2153b7f364920c04a743e0d95bd45fdc6e Mon Sep 17 00:00:00 2001 From: Anton Vasiliev Date: Tue, 5 Oct 2021 14:21:00 +0100 Subject: [PATCH] #2280 - Implement support for string type in php.ini --- Library/Backends/ZendEngine2/Backend.php | 6 +-- Library/Backends/ZendEngine3/Backend.php | 2 +- Library/Compiler.php | 29 ++++++------ .../FunctionCall/GlobalsGetOptimizer.php | 23 +++++----- .../FunctionCall/GlobalsSetOptimizer.php | 18 +++++--- config.json | 4 ++ ext/php_stub.h | 9 +--- ext/stub.c | 2 +- ext/stub/globals.zep.c | 44 +++++++++++++++++-- ext/stub/globals.zep.h | 16 +++++++ stub/globals.zep | 13 ++++++ tests/Extension/GlobalsTest.php | 16 +++++++ 12 files changed, 134 insertions(+), 48 deletions(-) diff --git a/Library/Backends/ZendEngine2/Backend.php b/Library/Backends/ZendEngine2/Backend.php index bed7a71055..1612743bf3 100644 --- a/Library/Backends/ZendEngine2/Backend.php +++ b/Library/Backends/ZendEngine2/Backend.php @@ -1102,12 +1102,12 @@ protected function assignHelper( return $output; } - protected function returnHelper($macro, $value, CompilationContext $context, $useCodePrinter, $doCopy = null) + protected function returnHelper(string $macro, $value, CompilationContext $context, $useCodePrinter, $doCopy = null): string { if ($value instanceof Variable) { $value = $value->getName(); - } else { - $value = 'RETURN_MM_STRING' == $macro ? '"'.$value.'"' : $value; + } elseif ($macro === 'RETURN_MM_STRING' && !preg_match('/^ZEPHIR_GLOBAL/', $value)) { + $value = '"'.$value.'"'; } $copyStr = ''; diff --git a/Library/Backends/ZendEngine3/Backend.php b/Library/Backends/ZendEngine3/Backend.php index 374d765c1f..011bb1a644 100644 --- a/Library/Backends/ZendEngine3/Backend.php +++ b/Library/Backends/ZendEngine3/Backend.php @@ -575,7 +575,7 @@ public function assignZval(Variable $variable, $code, CompilationContext $contex public function returnString($value, CompilationContext $context, $useCodePrinter = true, $doCopy = true) { - return $this->returnHelper('RETURN_MM_STRING', $value, $context, $useCodePrinter, null); + return $this->returnHelper('RETURN_MM_STRING', $value, $context, $useCodePrinter); } public function createClosure(Variable $variable, $classDefinition, CompilationContext $context) diff --git a/Library/Compiler.php b/Library/Compiler.php index ea21698c54..ce760f4c36 100644 --- a/Library/Compiler.php +++ b/Library/Compiler.php @@ -1325,7 +1325,7 @@ public function processExtensionGlobals(string $namespace): array $structBuilder->addProperty($field, $global); $isModuleGlobal = (int) !empty($global['module']); - $globalsDefault[$isModuleGlobal][] = $structBuilder->getCDefault($field, $global, $namespace).PHP_EOL; + $globalsDefault[$isModuleGlobal][] = $structBuilder->getCDefault($field, $global, $namespace); $initEntries[] = $structBuilder->getInitEntry($field, $global, $namespace); } @@ -1334,8 +1334,7 @@ public function processExtensionGlobals(string $namespace): array $globalCode = PHP_EOL; foreach ($structures as $structureName => $internalStructure) { - $globalCode .= "\t".'zephir_struct_'.$structureName.' '. - $structureName.';'.PHP_EOL.PHP_EOL; + $globalCode .= "\t".'zephir_struct_'.$structureName.' '.$structureName.';'.PHP_EOL; } /** @@ -1352,16 +1351,16 @@ public function processExtensionGlobals(string $namespace): array $isModuleGlobal = (int) !empty($global['module']); $type = $global['type']; - // TODO: Add support for 'string', 'hash' + // TODO: Add support for 'hash' // TODO: Zephir\Optimizers\FunctionCall\GlobalsSetOptimizer switch ($global['type']) { case 'boolean': case 'bool': $type = 'zend_bool'; if (true === $global['default']) { - $globalsDefault[$isModuleGlobal][] = "\t".$namespace.'_globals->'.$name.' = 1;'.PHP_EOL; + $globalsDefault[$isModuleGlobal][] = "\t".$namespace.'_globals->'.$name.' = 1;'; } else { - $globalsDefault[$isModuleGlobal][] = "\t".$namespace.'_globals->'.$name.' = 0;'.PHP_EOL; + $globalsDefault[$isModuleGlobal][] = "\t".$namespace.'_globals->'.$name.' = 0;'; } break; @@ -1369,16 +1368,16 @@ public function processExtensionGlobals(string $namespace): array case 'uint': case 'long': case 'double': - $globalsDefault[$isModuleGlobal][] - = "\t".$namespace.'_globals->'.$name.' = '. - $global['default'].';'.PHP_EOL; + $globalsDefault[$isModuleGlobal][] = "\t".$namespace.'_globals->'.$name.' = '.$global['default'].';'; break; case 'char': case 'uchar': - $globalsDefault[$isModuleGlobal][] - = "\t".$namespace.'_globals->'.$name.' = \''. - $global['default'].'\';'.PHP_EOL; + $globalsDefault[$isModuleGlobal][] = "\t".$namespace.'_globals->'.$name.' = \''.$global['default'].'\';'; + break; + case 'string': + $type = 'char *'; + $globalsDefault[$isModuleGlobal][] = "\t".$namespace.'_globals->'.$name.' = ZSTR_VAL(zend_string_init(ZEND_STRL("'.$global['default'].'"), 0));'; break; default: throw new Exception( @@ -1386,7 +1385,7 @@ public function processExtensionGlobals(string $namespace): array ); } - $globalCode .= "\t".$type.' '.$name.';'.PHP_EOL.PHP_EOL; + $globalCode .= "\t".$type.' '.$name.';'.PHP_EOL; $iniEntry = []; if (isset($global['ini-entry'])) { $iniEntry = $global['ini-entry']; @@ -1425,8 +1424,8 @@ public function processExtensionGlobals(string $namespace): array } } - $globalsDefault[0] = implode('', $globalsDefault[0]); - $globalsDefault[1] = implode('', $globalsDefault[1]); + $globalsDefault[0] = implode(PHP_EOL, $globalsDefault[0]); + $globalsDefault[1] = implode(PHP_EOL, $globalsDefault[1]); return [$globalCode, $globalStruct, $globalsDefault, $initEntries]; } diff --git a/Library/Optimizers/FunctionCall/GlobalsGetOptimizer.php b/Library/Optimizers/FunctionCall/GlobalsGetOptimizer.php index a6cdf43f12..da5dfdf259 100644 --- a/Library/Optimizers/FunctionCall/GlobalsGetOptimizer.php +++ b/Library/Optimizers/FunctionCall/GlobalsGetOptimizer.php @@ -9,6 +9,8 @@ * the LICENSE file that was distributed with this source code. */ +declare(strict_types=1); + namespace Zephir\Optimizers\FunctionCall; use Zephir\Call; @@ -17,8 +19,10 @@ use Zephir\Exception\CompilerException; use Zephir\Optimizers\OptimizerAbstract; +use function count; + /** - * GlobalsGetOptimizer. + * `globals_get()` internal function. * * Reads values from extensions globals */ @@ -29,21 +33,20 @@ class GlobalsGetOptimizer extends OptimizerAbstract * @param Call $call * @param CompilationContext $context * + * @return CompiledExpression|null * @throws CompilerException - * - * @return bool|CompiledExpression|mixed */ - public function optimize(array $expression, Call $call, CompilationContext $context) + public function optimize(array $expression, Call $call, CompilationContext $context): ?CompiledExpression { if (!isset($expression['parameters'])) { - return false; + return null; } - if (1 != \count($expression['parameters'])) { + if (1 !== count($expression['parameters'])) { throw new CompilerException("'globals_get' only accepts one parameter", $expression); } - if ('string' != $expression['parameters'][0]['parameter']['type']) { + if ('string' !== $expression['parameters'][0]['parameter']['type']) { throw new CompilerException("A string parameter is required for 'globals_get'", $expression); } @@ -53,14 +56,14 @@ public function optimize(array $expression, Call $call, CompilationContext $cont throw new CompilerException("Global '".$globalName."' cannot be read because it isn't defined", $expression); } - $globalDefinition = $context->compiler->getExtensionGlobal($globalName); + $type = $context->compiler->getExtensionGlobal($globalName)['type']; if (false !== strpos($globalName, '.')) { $parts = explode('.', $globalName); - return new CompiledExpression($globalDefinition['type'], 'ZEPHIR_GLOBAL('.$parts[0].').'.$parts[1], $expression); + return new CompiledExpression($type, 'ZEPHIR_GLOBAL('.$parts[0].').'.$parts[1], $expression); } - return new CompiledExpression($globalDefinition['type'], 'ZEPHIR_GLOBAL('.$globalName.')', $expression); + return new CompiledExpression($type, 'ZEPHIR_GLOBAL('.$globalName.')', $expression); } } diff --git a/Library/Optimizers/FunctionCall/GlobalsSetOptimizer.php b/Library/Optimizers/FunctionCall/GlobalsSetOptimizer.php index 457c70125c..5ff8573b52 100644 --- a/Library/Optimizers/FunctionCall/GlobalsSetOptimizer.php +++ b/Library/Optimizers/FunctionCall/GlobalsSetOptimizer.php @@ -9,6 +9,8 @@ * the LICENSE file that was distributed with this source code. */ +declare(strict_types=1); + namespace Zephir\Optimizers\FunctionCall; use Zephir\Call; @@ -18,10 +20,12 @@ use Zephir\Exception\CompilerException; use Zephir\Optimizers\OptimizerAbstract; +use function count; + /** - * Zephir\Optimizers\FunctionCall\GlobalsSetOptimizer. + * `globals_set()` internal function. * - * Writes values from extensions globals + * Writes values from extensions globals. */ class GlobalsSetOptimizer extends OptimizerAbstract { @@ -34,17 +38,17 @@ class GlobalsSetOptimizer extends OptimizerAbstract * * @return CompiledExpression */ - public function optimize(array $expression, Call $call, CompilationContext $context) + public function optimize(array $expression, Call $call, CompilationContext $context): CompiledExpression { if (!isset($expression['parameters'])) { throw new CompilerException("'globals_set' requires two parameters", $expression); } - if (2 != \count($expression['parameters'])) { + if (2 !== count($expression['parameters'])) { throw new CompilerException("'globals_set' only accepts two parameters", $expression); } - if ('string' != $expression['parameters'][0]['parameter']['type']) { + if ('string' !== $expression['parameters'][0]['parameter']['type']) { throw new CompilerException("A string parameter is required for 'globals_set'", $expression); } @@ -88,7 +92,7 @@ public function optimize(array $expression, Call $call, CompilationContext $cont } } - private function resolveInternalAccessor($globalName) + private function resolveInternalAccessor(string $globalName): string { $parts = explode('.', $globalName); @@ -124,7 +128,7 @@ private function resolveInternalValue(array $definition, array $expression, stri case 'ulong': return strtr('zval_get_long(:v)', [':v' => $value]); case 'string': - return strtr('zval_get_string(:v)', [':v' => $value]); + return strtr('ZSTR_VAL(zval_get_string(:v))', [':v' => $value]); case 'char': case 'uchar': return strtr( diff --git a/config.json b/config.json index 938950d06d..95978e34ec 100644 --- a/config.json +++ b/config.json @@ -95,6 +95,10 @@ "type": "char", "default": "A" }, + "my_setting_5": { + "type": "string", + "default": "custom_value" + }, "db.my_setting_1": { "type": "bool", "default": false diff --git a/ext/php_stub.h b/ext/php_stub.h index 28fcad82c4..17569fb1e7 100644 --- a/ext/php_stub.h +++ b/ext/php_stub.h @@ -51,21 +51,14 @@ ZEND_BEGIN_MODULE_GLOBALS(stub) zephir_struct_db db; - zephir_struct_orm orm; - zephir_struct_extension extension; - zend_bool my_setting_1; - zend_bool test_setting_1; - int my_setting_2; - double my_setting_3; - char my_setting_4; - + char * my_setting_5; ZEND_END_MODULE_GLOBALS(stub) diff --git a/ext/stub.c b/ext/stub.c index e1f353ba99..3e43e6fcb1 100644 --- a/ext/stub.c +++ b/ext/stub.c @@ -524,7 +524,7 @@ static void php_zephir_init_globals(zend_stub_globals *stub_globals) stub_globals->my_setting_2 = 10; stub_globals->my_setting_3 = 15.2; stub_globals->my_setting_4 = 'A'; - + stub_globals->my_setting_5 = ZSTR_VAL(zend_string_init(ZEND_STRL("custom_value"), 0)); } diff --git a/ext/stub/globals.zep.c b/ext/stub/globals.zep.c index 26e8618ea8..06647de6aa 100644 --- a/ext/stub/globals.zep.c +++ b/ext/stub/globals.zep.c @@ -14,6 +14,7 @@ #include "kernel/main.h" #include "kernel/memory.h" #include "kernel/object.h" +#include "kernel/operators.h" ZEPHIR_INIT_CLASS(Stub_Globals) @@ -60,7 +61,7 @@ PHP_METHOD(Stub_Globals, setIntValueUsingDotNotation) zephir_fetch_params_without_memory_grow(1, 0, &value); - ZEPHIR_GLOBAL(db).my_setting_2 = Z_LVAL_P(value); + ZEPHIR_GLOBAL(db).my_setting_2 = zval_get_long(value); } PHP_METHOD(Stub_Globals, setCharValue) @@ -80,7 +81,32 @@ PHP_METHOD(Stub_Globals, setCharValue) zephir_fetch_params_without_memory_grow(1, 0, &value); - ZEPHIR_GLOBAL(my_setting_4) = (Z_TYPE_P(value) == IS_STRING ? (Z_STRLEN_P(value) ? Z_STRVAL_P(value)[0] : NULL) : Z_LVAL_P(value)); + ZEPHIR_GLOBAL(my_setting_4) = (Z_TYPE_P(value) == IS_STRING ? (Z_STRLEN_P(value) ? Z_STRVAL_P(value)[0] : NULL) : zval_get_long(value)); +} + +PHP_METHOD(Stub_Globals, setStringValue) +{ + zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL; + zval *value_param = NULL; + zval value; + zval *this_ptr = getThis(); + + ZVAL_UNDEF(&value); +#if PHP_VERSION_ID >= 80000 + bool is_null_true = 1; + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(value) + ZEND_PARSE_PARAMETERS_END(); +#endif + + + ZEPHIR_MM_GROW(); + zephir_fetch_params(1, 1, 0, &value_param); + zephir_get_strval(&value, value_param); + + + ZEPHIR_GLOBAL(my_setting_5) = ZSTR_VAL(zval_get_string(&value)); + ZEPHIR_MM_RESTORE(); } PHP_METHOD(Stub_Globals, setBoolValue) @@ -120,7 +146,7 @@ PHP_METHOD(Stub_Globals, setDefaultGlobalsOrmCacheLevel) zephir_fetch_params_without_memory_grow(1, 0, &value); - ZEPHIR_GLOBAL(orm).cache_level = Z_LVAL_P(value); + ZEPHIR_GLOBAL(orm).cache_level = zval_get_long(value); } /** @@ -207,6 +233,18 @@ PHP_METHOD(Stub_Globals, getDefaultGlobals7) RETURN_LONG(ZEPHIR_GLOBAL(my_setting_4)); } +/** + * @return mixed + */ +PHP_METHOD(Stub_Globals, getDefaultGlobals8) +{ + zval *this_ptr = getThis(); + + + + RETURN_STRING(ZEPHIR_GLOBAL(my_setting_5)); +} + /** * @return mixed */ diff --git a/ext/stub/globals.zep.h b/ext/stub/globals.zep.h index 25887d0210..b8198d31ce 100644 --- a/ext/stub/globals.zep.h +++ b/ext/stub/globals.zep.h @@ -6,6 +6,7 @@ ZEPHIR_INIT_CLASS(Stub_Globals); PHP_METHOD(Stub_Globals, setBoolValueUsingDotNotation); PHP_METHOD(Stub_Globals, setIntValueUsingDotNotation); PHP_METHOD(Stub_Globals, setCharValue); +PHP_METHOD(Stub_Globals, setStringValue); PHP_METHOD(Stub_Globals, setBoolValue); PHP_METHOD(Stub_Globals, setDefaultGlobalsOrmCacheLevel); PHP_METHOD(Stub_Globals, getDefaultGlobals1); @@ -15,6 +16,7 @@ PHP_METHOD(Stub_Globals, getDefaultGlobals4); PHP_METHOD(Stub_Globals, getDefaultGlobals5); PHP_METHOD(Stub_Globals, getDefaultGlobals6); PHP_METHOD(Stub_Globals, getDefaultGlobals7); +PHP_METHOD(Stub_Globals, getDefaultGlobals8); PHP_METHOD(Stub_Globals, getDefaultGlobalsOrmCacheLevel); ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stub_globals_setboolvalueusingdotnotation, 0, 1, IS_VOID, 0) @@ -32,6 +34,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stub_globals_setcharvalue, 0, 1, ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stub_globals_setstringvalue, 0, 1, IS_VOID, 0) + + ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_stub_globals_setboolvalue, 0, 1, IS_VOID, 0) ZEND_ARG_INFO(0, value) @@ -63,6 +70,9 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_stub_globals_getdefaultglobals7, 0, 0, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_stub_globals_getdefaultglobals8, 0, 0, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(arginfo_stub_globals_getdefaultglobalsormcachelevel, 0, 0, 0) ZEND_END_ARG_INFO() @@ -70,6 +80,7 @@ ZEPHIR_INIT_FUNCS(stub_globals_method_entry) { PHP_ME(Stub_Globals, setBoolValueUsingDotNotation, arginfo_stub_globals_setboolvalueusingdotnotation, ZEND_ACC_PUBLIC) PHP_ME(Stub_Globals, setIntValueUsingDotNotation, arginfo_stub_globals_setintvalueusingdotnotation, ZEND_ACC_PUBLIC) PHP_ME(Stub_Globals, setCharValue, arginfo_stub_globals_setcharvalue, ZEND_ACC_PUBLIC) + PHP_ME(Stub_Globals, setStringValue, arginfo_stub_globals_setstringvalue, ZEND_ACC_PUBLIC) PHP_ME(Stub_Globals, setBoolValue, arginfo_stub_globals_setboolvalue, ZEND_ACC_PUBLIC) PHP_ME(Stub_Globals, setDefaultGlobalsOrmCacheLevel, arginfo_stub_globals_setdefaultglobalsormcachelevel, ZEND_ACC_PUBLIC) #if PHP_VERSION_ID >= 80000 @@ -107,6 +118,11 @@ ZEPHIR_INIT_FUNCS(stub_globals_method_entry) { #else PHP_ME(Stub_Globals, getDefaultGlobals7, NULL, ZEND_ACC_PUBLIC) #endif +#if PHP_VERSION_ID >= 80000 + PHP_ME(Stub_Globals, getDefaultGlobals8, arginfo_stub_globals_getdefaultglobals8, ZEND_ACC_PUBLIC) +#else + PHP_ME(Stub_Globals, getDefaultGlobals8, NULL, ZEND_ACC_PUBLIC) +#endif #if PHP_VERSION_ID >= 80000 PHP_ME(Stub_Globals, getDefaultGlobalsOrmCacheLevel, arginfo_stub_globals_getdefaultglobalsormcachelevel, ZEND_ACC_PUBLIC) #else diff --git a/stub/globals.zep b/stub/globals.zep index bd8c2f302b..4b36341eb7 100644 --- a/stub/globals.zep +++ b/stub/globals.zep @@ -20,6 +20,11 @@ class Globals globals_set("my_setting_4", value); } + public function setStringValue(string value) -> void + { + globals_set("my_setting_5", value); + } + public function setBoolValue(value) -> void { globals_set("my_setting_1", value); @@ -88,6 +93,14 @@ class Globals return globals_get("my_setting_4"); } + /** + * @return mixed + */ + public function getDefaultGlobals8() + { + return globals_get("my_setting_5"); + } + /** * @return mixed */ diff --git a/tests/Extension/GlobalsTest.php b/tests/Extension/GlobalsTest.php index c95191f1e8..0f7fa66871 100644 --- a/tests/Extension/GlobalsTest.php +++ b/tests/Extension/GlobalsTest.php @@ -39,6 +39,7 @@ public function testShouldGetGlobalExtensionSettings(): void $this->assertSame(10, $this->test->getDefaultGlobals5()); $this->assertSame(15.2, $this->test->getDefaultGlobals6()); $this->assertSame(65, $this->test->getDefaultGlobals7()); + $this->assertSame('custom_value', $this->test->getDefaultGlobals8()); } public function testShouldSetGlobalExtensionSetting(): void @@ -69,6 +70,21 @@ public function testSetCharValueUsingInt(): void $this->assertSame(90, $this->test->getDefaultGlobals7()); } + public function testSetStringValue(): void + { + $this->test->setStringValue('1'); + $this->assertSame('1', $this->test->getDefaultGlobals8()); + + $this->test->setStringValue('c'); + $this->assertSame('c', $this->test->getDefaultGlobals8()); + + $this->test->setStringValue('char'); + $this->assertSame('char', $this->test->getDefaultGlobals8()); + + $this->test->setStringValue('Long Text without any sense...'); + $this->assertSame('Long Text without any sense...', $this->test->getDefaultGlobals8()); + } + public function testSetBoolValueUsingInt(): void { $this->test->setBoolValue(0);