mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Add support for generating optimizer function info from stubs (#7367)
This commit is contained in:
parent
3be94217f4
commit
b1822899fc
11 changed files with 548 additions and 161 deletions
|
@ -47,6 +47,8 @@ typedef struct _func_info_t {
|
|||
#define FC(name, callback) \
|
||||
{name, sizeof(name)-1, 0, callback}
|
||||
|
||||
#include "zend_func_infos.h"
|
||||
|
||||
static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa *ssa)
|
||||
{
|
||||
if (!call_info->send_unpack
|
||||
|
@ -85,34 +87,21 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
|
|||
}
|
||||
}
|
||||
|
||||
static const func_info_t func_infos[] = {
|
||||
static const func_info_t old_func_infos[] = {
|
||||
/* zend */
|
||||
F1("zend_version", MAY_BE_STRING),
|
||||
FN("func_get_args", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("get_class_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
|
||||
F1("get_class_methods", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
F1("get_included_files", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
FN("set_error_handler", MAY_BE_NULL | MAY_BE_STRING | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_OBJECT | MAY_BE_OBJECT),
|
||||
F0("restore_error_handler", MAY_BE_TRUE),
|
||||
F0("restore_exception_handler", MAY_BE_TRUE),
|
||||
F1("get_declared_traits", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
F1("get_declared_classes", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
F1("get_declared_interfaces", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
F1("get_defined_functions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
|
||||
F1("get_defined_vars", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF),
|
||||
F1("get_resource_type", MAY_BE_STRING),
|
||||
F1("get_defined_constants", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("debug_backtrace", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
|
||||
F1("get_loaded_extensions", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
F1("get_extension_funcs", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
|
||||
/* ext/standard */
|
||||
FN("constant", MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("bin2hex", MAY_BE_STRING),
|
||||
F1("hex2bin", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
#if HAVE_NANOSLEEP
|
||||
F1("time_nanosleep", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG),
|
||||
#endif
|
||||
#if HAVE_STRPTIME
|
||||
F1("strptime", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
#endif
|
||||
|
@ -191,7 +180,6 @@ static const func_info_t func_infos[] = {
|
|||
F0("passthru", MAY_BE_NULL | MAY_BE_FALSE),
|
||||
F1("shell_exec", MAY_BE_NULL | MAY_BE_FALSE | MAY_BE_STRING),
|
||||
#ifdef PHP_CAN_SUPPORT_PROC_OPEN
|
||||
F1("proc_open", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("proc_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_FALSE | MAY_BE_ARRAY_OF_TRUE | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
#endif
|
||||
F1("random_bytes", MAY_BE_STRING),
|
||||
|
@ -266,30 +254,14 @@ static const func_info_t func_infos[] = {
|
|||
#ifdef HAVE_GETHOSTNAME
|
||||
F1("gethostname", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
#endif
|
||||
#if defined(PHP_WIN32) || HAVE_DNS_SEARCH_FUNC
|
||||
# if defined(PHP_WIN32) || HAVE_FULL_DNS_FUNCS
|
||||
F1("dns_get_record", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ARRAY),
|
||||
# endif
|
||||
#endif
|
||||
F1("popen", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("fgets", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("fread", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("fopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("fstat", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_LONG),
|
||||
F1("tempnam", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("tmpfile", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("file", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
F1("file_get_contents", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("stream_context_create", MAY_BE_RESOURCE),
|
||||
F1("stream_context_get_params", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
|
||||
FN("stream_context_get_options", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
|
||||
FN("stream_context_get_default", MAY_BE_RESOURCE),
|
||||
FN("stream_context_set_default", MAY_BE_RESOURCE),
|
||||
FN("stream_filter_prepend", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
FN("stream_filter_append", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("stream_socket_client", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("stream_socket_server", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("stream_socket_accept", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("stream_socket_get_name", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("stream_socket_recvfrom", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
#if HAVE_SOCKETPAIR
|
||||
|
@ -306,13 +278,10 @@ static const func_info_t func_infos[] = {
|
|||
F1("get_headers", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_STRING | MAY_BE_ARRAY_OF_ARRAY),
|
||||
F1("socket_get_status", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("realpath", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("fsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
FN("pfsockopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("pack", MAY_BE_STRING),
|
||||
F1("unpack", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("get_browser", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_OBJECT | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("crypt", MAY_BE_STRING),
|
||||
FN("opendir", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("getcwd", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("readdir", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("dir", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
|
@ -542,7 +511,6 @@ static const func_info_t func_infos[] = {
|
|||
F1("utf8_decode", MAY_BE_STRING),
|
||||
|
||||
/* ext/zlib */
|
||||
F1("gzopen", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("gzfile", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING),
|
||||
F1("gzcompress", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
F1("gzuncompress", MAY_BE_FALSE | MAY_BE_STRING),
|
||||
|
@ -686,7 +654,6 @@ static const func_info_t func_infos[] = {
|
|||
F1("pg_get_result", MAY_BE_FALSE | MAY_BE_OBJECT),
|
||||
F1("pg_result_status", MAY_BE_LONG | MAY_BE_STRING),
|
||||
F1("pg_get_notify", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("pg_socket", MAY_BE_FALSE | MAY_BE_RESOURCE),
|
||||
F1("pg_meta_data", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ARRAY),
|
||||
F1("pg_convert", MAY_BE_FALSE | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_STRING | MAY_BE_ARRAY_OF_ANY),
|
||||
F1("pg_insert", MAY_BE_FALSE | MAY_BE_TRUE | MAY_BE_OBJECT | MAY_BE_STRING),
|
||||
|
@ -889,25 +856,33 @@ ZEND_API uint32_t zend_get_func_info(
|
|||
return ret;
|
||||
}
|
||||
|
||||
int zend_func_info_startup(void)
|
||||
void zend_func_info_add(const func_info_t *func_infos, size_t n)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
zend_string *key = zend_string_init_interned(func_infos[i].name, func_infos[i].name_len, 1);
|
||||
|
||||
if (zend_hash_add_ptr(&func_info, key, (void**)&func_infos[i]) == NULL) {
|
||||
fprintf(stderr, "ERROR: Duplicate function info for \"%s\"\n", func_infos[i].name);
|
||||
}
|
||||
|
||||
zend_string_release_ex(key, 1);
|
||||
}
|
||||
}
|
||||
|
||||
int zend_func_info_startup(void)
|
||||
{
|
||||
if (zend_func_info_rid == -1) {
|
||||
zend_func_info_rid = zend_get_resource_handle("Zend Optimizer");
|
||||
if (zend_func_info_rid < 0) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
zend_hash_init(&func_info, sizeof(func_infos)/sizeof(func_info_t), NULL, NULL, 1);
|
||||
for (i = 0; i < sizeof(func_infos)/sizeof(func_info_t); i++) {
|
||||
zend_string *key = zend_string_init_interned(func_infos[i].name, func_infos[i].name_len, 1);
|
||||
zend_hash_init(&func_info, sizeof(old_func_infos)/sizeof(func_info_t) + sizeof(func_infos)/sizeof(func_info_t), NULL, NULL, 1);
|
||||
|
||||
if (zend_hash_add_ptr(&func_info, key, (void**)&func_infos[i]) == NULL) {
|
||||
fprintf(stderr, "ERROR: Duplicate function info for \"%s\"\n", func_infos[i].name);
|
||||
}
|
||||
zend_string_release_ex(key, 1);
|
||||
}
|
||||
zend_func_info_add(old_func_infos, sizeof(old_func_infos)/sizeof(func_info_t));
|
||||
zend_func_info_add(func_infos, sizeof(func_infos)/sizeof(func_info_t));
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
|
|
49
Zend/Optimizer/zend_func_infos.h
Normal file
49
Zend/Optimizer/zend_func_infos.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* This is a generated file, edit the .stub.php files instead. */
|
||||
|
||||
static const func_info_t func_infos[] = {
|
||||
F1("zend_version", MAY_BE_STRING),
|
||||
FN("func_get_args", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ANY),
|
||||
F1("get_class_methods", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
|
||||
F1("get_included_files", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING),
|
||||
FN("set_error_handler", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_OBJECT|MAY_BE_NULL),
|
||||
F0("restore_error_handler", MAY_BE_TRUE),
|
||||
FN("set_exception_handler", MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_OBJECT|MAY_BE_NULL),
|
||||
F0("restore_exception_handler", MAY_BE_TRUE),
|
||||
F1("get_resource_type", MAY_BE_STRING),
|
||||
F1("get_defined_constants", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_ANY),
|
||||
FN("socket_export_stream", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("gzopen", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
#if HAVE_NANOSLEEP
|
||||
F1("time_nanosleep", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_LONG|MAY_BE_BOOL),
|
||||
#endif
|
||||
#if defined(PHP_WIN32) || HAVE_DNS_SEARCH_FUNC
|
||||
F1("dns_get_record", MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_LONG|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_FALSE),
|
||||
#endif
|
||||
FN("opendir", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("popen", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("fopen", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("tmpfile", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("fsockopen", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("pfsockopen", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
#if defined(PHP_CAN_SUPPORT_PROC_OPEN)
|
||||
F1("proc_open", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
#endif
|
||||
F1("stream_context_create", MAY_BE_RESOURCE),
|
||||
FN("stream_context_get_default", MAY_BE_RESOURCE),
|
||||
FN("stream_context_set_default", MAY_BE_RESOURCE),
|
||||
FN("stream_filter_prepend", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("stream_filter_append", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("stream_socket_client", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("stream_socket_server", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("stream_socket_accept", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("zip_open", MAY_BE_RESOURCE|MAY_BE_LONG|MAY_BE_FALSE),
|
||||
FN("zip_read", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("oci_new_connect", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("oci_connect", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("oci_pconnect", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("oci_parse", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("oci_get_implicit_resultset", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
FN("oci_password_change", MAY_BE_RESOURCE|MAY_BE_BOOL),
|
||||
FN("oci_new_cursor", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
F1("pg_socket", MAY_BE_RESOURCE|MAY_BE_FALSE),
|
||||
};
|
|
@ -6,12 +6,14 @@ class stdClass
|
|||
{
|
||||
}
|
||||
|
||||
/** @refcount 1 */
|
||||
function zend_version(): string {}
|
||||
|
||||
function func_num_args(): int {}
|
||||
|
||||
function func_get_arg(int $position): mixed {}
|
||||
|
||||
/** @return array<int, mixed> */
|
||||
function func_get_args(): array {}
|
||||
|
||||
function strlen(string $string): int {}
|
||||
|
@ -48,6 +50,10 @@ function get_object_vars(object $object): array {}
|
|||
|
||||
function get_mangled_object_vars(object $object): array {}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
* @refcount 1
|
||||
*/
|
||||
function get_class_methods(object|string $object_or_class): array {}
|
||||
|
||||
/** @param object|string $object_or_class */
|
||||
|
@ -68,9 +74,16 @@ function function_exists(string $function): bool {}
|
|||
|
||||
function class_alias(string $class, string $alias, bool $autoload = true): bool {}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
* @refcount 1
|
||||
*/
|
||||
function get_included_files(): array {}
|
||||
|
||||
/** @alias get_included_files */
|
||||
/**
|
||||
* @return array<int, string>
|
||||
* @alias get_included_files
|
||||
*/
|
||||
function get_required_files(): array {}
|
||||
|
||||
function trigger_error(string $message, int $error_level = E_USER_NOTICE): bool {}
|
||||
|
@ -78,14 +91,16 @@ function trigger_error(string $message, int $error_level = E_USER_NOTICE): bool
|
|||
/** @alias trigger_error */
|
||||
function user_error(string $message, int $error_level = E_USER_NOTICE): bool {}
|
||||
|
||||
/** @return string|array|object|null */
|
||||
/** @return string|array<int, string|object>|object|null */
|
||||
function set_error_handler(?callable $callback, int $error_levels = E_ALL) {}
|
||||
|
||||
/** @return true */
|
||||
function restore_error_handler(): bool {}
|
||||
|
||||
/** @return string|array|object|null */
|
||||
/** @return string|array<int, string|object>|object|null */
|
||||
function set_exception_handler(?callable $callback) {}
|
||||
|
||||
/** @return true */
|
||||
function restore_exception_handler(): bool {}
|
||||
|
||||
function get_declared_classes(): array {}
|
||||
|
@ -98,7 +113,10 @@ function get_defined_functions(bool $exclude_disabled = true): array {}
|
|||
|
||||
function get_defined_vars(): array {}
|
||||
|
||||
/** @param resource $resource */
|
||||
/**
|
||||
* @param resource $resource
|
||||
* @refcount 1
|
||||
*/
|
||||
function get_resource_type($resource): string {}
|
||||
|
||||
/** @param resource $resource */
|
||||
|
@ -108,6 +126,10 @@ function get_resources(?string $type = null): array {}
|
|||
|
||||
function get_loaded_extensions(bool $zend_extensions = false): array {}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
* @refcount 1
|
||||
*/
|
||||
function get_defined_constants(bool $categorize = false): array {}
|
||||
|
||||
function debug_backtrace(int $options = DEBUG_BACKTRACE_PROVIDE_OBJECT, int $limit = 0): array {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 38936b472d60d9eeb2cc8e35c1276e9f707837bf */
|
||||
* Stub hash: c8a0a1e4cfece42832f737b33e317ba88b91fab5 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_version, 0, 0, IS_STRING, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
|
|
@ -107,22 +107,59 @@ class Context {
|
|||
public $forceRegeneration = false;
|
||||
}
|
||||
|
||||
class ArrayType extends SimpleType {
|
||||
/** @var Type */
|
||||
public $keyType;
|
||||
|
||||
/** @var Type */
|
||||
public $valueType;
|
||||
|
||||
public static function createGenericArray(): self
|
||||
{
|
||||
return new ArrayType(Type::fromString("int|string"), Type::fromString("mixed"));
|
||||
}
|
||||
|
||||
public function __construct(Type $keyType, Type $valueType)
|
||||
{
|
||||
parent::__construct("array", true);
|
||||
|
||||
$this->keyType = $keyType;
|
||||
$this->valueType = $valueType;
|
||||
}
|
||||
|
||||
public function toOptimizerTypeMask(): string {
|
||||
$typeMasks = [
|
||||
parent::toOptimizerTypeMask(),
|
||||
$this->keyType->toOptimizerTypeMaskForArrayKey(),
|
||||
$this->valueType->toOptimizerTypeMaskForArrayValue(),
|
||||
];
|
||||
|
||||
return implode("|", $typeMasks);
|
||||
}
|
||||
|
||||
public function equals(SimpleType $other): bool {
|
||||
if (!parent::equals($other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(get_class($other) === self::class);
|
||||
|
||||
return Type::equals($this->keyType, $other->keyType) &&
|
||||
Type::equals($this->valueType, $other->valueType);
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleType {
|
||||
/** @var string */
|
||||
public $name;
|
||||
/** @var bool */
|
||||
public $isBuiltin;
|
||||
|
||||
public function __construct(string $name, bool $isBuiltin) {
|
||||
$this->name = $name;
|
||||
$this->isBuiltin = $isBuiltin;
|
||||
}
|
||||
|
||||
public static function fromNode(Node $node): SimpleType {
|
||||
if ($node instanceof Node\Name) {
|
||||
if ($node->toLowerString() === 'static') {
|
||||
// PHP internally considers "static" a builtin type.
|
||||
return new SimpleType($node->toString(), true);
|
||||
return new SimpleType($node->toLowerString(), true);
|
||||
}
|
||||
|
||||
if ($node->toLowerString() === 'self') {
|
||||
|
@ -132,39 +169,55 @@ class SimpleType {
|
|||
assert($node->isFullyQualified());
|
||||
return new SimpleType($node->toString(), false);
|
||||
}
|
||||
|
||||
if ($node instanceof Node\Identifier) {
|
||||
return new SimpleType($node->toString(), true);
|
||||
if ($node->toLowerString() === 'array') {
|
||||
return ArrayType::createGenericArray();
|
||||
}
|
||||
|
||||
return new SimpleType($node->toLowerString(), true);
|
||||
}
|
||||
|
||||
throw new Exception("Unexpected node type");
|
||||
}
|
||||
|
||||
public static function fromPhpDoc(string $type): SimpleType
|
||||
public static function fromString(string $typeString): SimpleType
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
switch (strtolower($typeString)) {
|
||||
case "void":
|
||||
case "null":
|
||||
case "false":
|
||||
case "true":
|
||||
case "bool":
|
||||
case "int":
|
||||
case "float":
|
||||
case "string":
|
||||
case "array":
|
||||
case "iterable":
|
||||
case "object":
|
||||
case "resource":
|
||||
case "mixed":
|
||||
case "static":
|
||||
case "never":
|
||||
return new SimpleType(strtolower($type), true);
|
||||
return new SimpleType(strtolower($typeString), true);
|
||||
case "array":
|
||||
return ArrayType::createGenericArray();
|
||||
case "self":
|
||||
throw new Exception('The exact class name must be used instead of "self"');
|
||||
}
|
||||
|
||||
if (strpos($type, "[]") !== false) {
|
||||
return new SimpleType("array", true);
|
||||
$matches = [];
|
||||
$isArray = preg_match("/(.*)\s*\[\s*\]/", $typeString, $matches);
|
||||
if ($isArray) {
|
||||
return new ArrayType(Type::fromString("int"), Type::fromString($matches[1]));
|
||||
}
|
||||
|
||||
return new SimpleType($type, false);
|
||||
$matches = [];
|
||||
$isArray = preg_match("/array\s*<\s*([A-Za-z0-9_-|]+)\s*,\s*([A-Za-z0-9_-|]+)\s*>/i", $typeString, $matches);
|
||||
if ($isArray) {
|
||||
return new ArrayType(Type::fromString($matches[1]), Type::fromString($matches[2]));
|
||||
}
|
||||
|
||||
return new SimpleType($typeString, false);
|
||||
}
|
||||
|
||||
public static function null(): SimpleType
|
||||
|
@ -177,13 +230,22 @@ class SimpleType {
|
|||
return new SimpleType("void", true);
|
||||
}
|
||||
|
||||
protected function __construct(string $name, bool $isBuiltin) {
|
||||
$this->name = $name;
|
||||
$this->isBuiltin = $isBuiltin;
|
||||
}
|
||||
|
||||
public function isScalar(): bool {
|
||||
return $this->isBuiltin && in_array($this->name, ["null", "false", "true", "bool", "int", "float"], true);
|
||||
}
|
||||
|
||||
public function isNull(): bool {
|
||||
return $this->isBuiltin && $this->name === 'null';
|
||||
}
|
||||
|
||||
public function toTypeCode(): string {
|
||||
assert($this->isBuiltin);
|
||||
switch (strtolower($this->name)) {
|
||||
switch ($this->name) {
|
||||
case "bool":
|
||||
return "_IS_BOOL";
|
||||
case "int":
|
||||
|
@ -213,9 +275,10 @@ class SimpleType {
|
|||
}
|
||||
}
|
||||
|
||||
public function toTypeMask() {
|
||||
public function toTypeMask(): string {
|
||||
assert($this->isBuiltin);
|
||||
switch (strtolower($this->name)) {
|
||||
|
||||
switch ($this->name) {
|
||||
case "null":
|
||||
return "MAY_BE_NULL";
|
||||
case "false":
|
||||
|
@ -245,20 +308,86 @@ class SimpleType {
|
|||
}
|
||||
}
|
||||
|
||||
public function toOptimizerTypeMaskForArrayKey(): string {
|
||||
assert($this->isBuiltin);
|
||||
|
||||
switch ($this->name) {
|
||||
case "int":
|
||||
return "MAY_BE_ARRAY_KEY_LONG";
|
||||
case "string":
|
||||
return "MAY_BE_ARRAY_KEY_STRING";
|
||||
default:
|
||||
throw new Exception("Type $this->name cannot be an array key");
|
||||
}
|
||||
}
|
||||
|
||||
public function toOptimizerTypeMaskForArrayValue(): string {
|
||||
if (!$this->isBuiltin) {
|
||||
return "MAY_BE_ARRAY_OF_OBJECT";
|
||||
}
|
||||
|
||||
switch ($this->name) {
|
||||
case "null":
|
||||
return "MAY_BE_ARRAY_OF_NULL";
|
||||
case "false":
|
||||
return "MAY_BE_ARRAY_OF_FALSE";
|
||||
case "bool":
|
||||
return "MAY_BE_ARRAY_OF_FALSE|MAY_BE_ARRAY_OF_TRUE";
|
||||
case "int":
|
||||
return "MAY_BE_ARRAY_OF_LONG";
|
||||
case "float":
|
||||
return "MAY_BE_ARRAY_OF_DOUBLE";
|
||||
case "string":
|
||||
return "MAY_BE_ARRAY_OF_STRING";
|
||||
case "array":
|
||||
return "MAY_BE_ARRAY_OF_ARRAY";
|
||||
case "object":
|
||||
return "MAY_BE_ARRAY_OF_OBJECT";
|
||||
case "resource":
|
||||
return "MAY_BE_ARRAY_OF_RESOURCE";
|
||||
case "mixed":
|
||||
return "MAY_BE_ARRAY_OF_ANY";
|
||||
default:
|
||||
throw new Exception("Type $this->name cannot be an array value");
|
||||
}
|
||||
}
|
||||
|
||||
public function toOptimizerTypeMask(): string {
|
||||
if (!$this->isBuiltin) {
|
||||
return "MAY_BE_OBJECT";
|
||||
}
|
||||
|
||||
if ($this->name === "resource") {
|
||||
return "MAY_BE_RESOURCE";
|
||||
}
|
||||
|
||||
if ($this->name === "true") {
|
||||
return "MAY_BE_TRUE";
|
||||
}
|
||||
|
||||
if ($this->name === "mixed") {
|
||||
return "MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY";
|
||||
}
|
||||
|
||||
return $this->toTypeMask();
|
||||
}
|
||||
|
||||
public function toEscapedName(): string {
|
||||
return str_replace('\\', '\\\\', $this->name);
|
||||
}
|
||||
|
||||
public function equals(SimpleType $other) {
|
||||
return $this->name === $other->name
|
||||
&& $this->isBuiltin === $other->isBuiltin;
|
||||
public function equals(SimpleType $other): bool {
|
||||
return $this->name === $other->name && $this->isBuiltin === $other->isBuiltin;
|
||||
}
|
||||
}
|
||||
|
||||
class Type {
|
||||
/** @var SimpleType[] $types */
|
||||
/** @var SimpleType[] */
|
||||
public $types;
|
||||
|
||||
/**
|
||||
* @param SimpleType[] $types
|
||||
*/
|
||||
public function __construct(array $types) {
|
||||
$this->types = $types;
|
||||
}
|
||||
|
@ -276,23 +405,58 @@ class Type {
|
|||
return new Type([SimpleType::fromNode($node)]);
|
||||
}
|
||||
|
||||
public static function fromPhpDoc(string $phpDocType) {
|
||||
$types = explode("|", $phpDocType);
|
||||
|
||||
public static function fromString(string $typeString): self {
|
||||
$typeString .= "|";
|
||||
$simpleTypes = [];
|
||||
foreach ($types as $type) {
|
||||
$simpleTypes[] = SimpleType::fromPhpDoc($type);
|
||||
$simpleTypeOffset = 0;
|
||||
$inArray = false;
|
||||
|
||||
$typeStringLength = strlen($typeString);
|
||||
for ($i = 0; $i < $typeStringLength; $i++) {
|
||||
$char = $typeString[$i];
|
||||
|
||||
if ($char === "<") {
|
||||
$inArray = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($char === ">") {
|
||||
$inArray = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($inArray) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($char === "|") {
|
||||
$simpleTypeName = trim(substr($typeString, $simpleTypeOffset, $i - $simpleTypeOffset));
|
||||
$simpleTypes[] = SimpleType::fromString($simpleTypeName);
|
||||
|
||||
$simpleTypeOffset = $i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return new Type($simpleTypes);
|
||||
}
|
||||
|
||||
public function isScalar(): bool {
|
||||
foreach ($this->types as $type) {
|
||||
if (!$type->isScalar()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isNullable(): bool {
|
||||
foreach ($this->types as $type) {
|
||||
if ($type->isNull()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -323,6 +487,36 @@ class Type {
|
|||
return new ArginfoType($classTypes, $builtinTypes);
|
||||
}
|
||||
|
||||
public function toOptimizerTypeMask(): string {
|
||||
$optimizerTypes = [];
|
||||
|
||||
foreach ($this->types as $type) {
|
||||
$optimizerTypes[] = $type->toOptimizerTypeMask();
|
||||
}
|
||||
|
||||
return implode("|", $optimizerTypes);
|
||||
}
|
||||
|
||||
public function toOptimizerTypeMaskForArrayKey(): string {
|
||||
$typeMasks = [];
|
||||
|
||||
foreach ($this->types as $type) {
|
||||
$typeMasks[] = $type->toOptimizerTypeMaskForArrayKey();
|
||||
}
|
||||
|
||||
return implode("|", $typeMasks);
|
||||
}
|
||||
|
||||
public function toOptimizerTypeMaskForArrayValue(): string {
|
||||
$typeMasks = [];
|
||||
|
||||
foreach ($this->types as $type) {
|
||||
$typeMasks[] = $type->toOptimizerTypeMaskForArrayValue();
|
||||
}
|
||||
|
||||
return implode("|", $typeMasks);
|
||||
}
|
||||
|
||||
public function getTypeForDoc(DOMDocument $doc): DOMElement {
|
||||
if (count($this->types) > 1) {
|
||||
$typeElement = $doc->createElement('type');
|
||||
|
@ -333,7 +527,14 @@ class Type {
|
|||
$typeElement->appendChild($unionTypeElement);
|
||||
}
|
||||
} else {
|
||||
$typeElement = $doc->createElement('type', $this->types[0]->name);
|
||||
$type = $this->types[0];
|
||||
if ($type->isBuiltin && strtolower($type->name) === "true") {
|
||||
$name = "bool";
|
||||
} else {
|
||||
$name = $type->name;
|
||||
}
|
||||
|
||||
$typeElement = $doc->createElement('type', $name);
|
||||
}
|
||||
|
||||
return $typeElement;
|
||||
|
@ -423,8 +624,7 @@ class ArgInfo {
|
|||
$this->name = $name;
|
||||
$this->sendBy = $sendBy;
|
||||
$this->isVariadic = $isVariadic;
|
||||
$this->type = $type;
|
||||
$this->phpDocType = $phpDocType;
|
||||
$this->setTypes($type, $phpDocType);
|
||||
$this->defaultValue = $defaultValue;
|
||||
}
|
||||
|
||||
|
@ -488,6 +688,16 @@ class ArgInfo {
|
|||
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
private function setTypes(?Type $type, ?Type $phpDocType): void
|
||||
{
|
||||
if ($phpDocType !== null && Type::equals($type, $phpDocType)) {
|
||||
throw new Exception('PHPDoc param type "' . $phpDocType->__toString() . '" is unnecessary');
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
$this->phpDocType = $phpDocType;
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyName {
|
||||
|
@ -619,6 +829,16 @@ class MethodName implements FunctionOrMethodName {
|
|||
}
|
||||
|
||||
class ReturnInfo {
|
||||
const REFCOUNT_0 = "0";
|
||||
const REFCOUNT_1 = "1";
|
||||
const REFCOUNT_N = "N";
|
||||
|
||||
const REFCOUNTS = [
|
||||
self::REFCOUNT_0,
|
||||
self::REFCOUNT_1,
|
||||
self::REFCOUNT_N,
|
||||
];
|
||||
|
||||
/** @var bool */
|
||||
public $byRef;
|
||||
/** @var Type|null */
|
||||
|
@ -627,15 +847,16 @@ class ReturnInfo {
|
|||
public $phpDocType;
|
||||
/** @var bool */
|
||||
public $tentativeReturnType;
|
||||
/** @var string */
|
||||
public $refcount;
|
||||
|
||||
public function __construct(bool $byRef, ?Type $type, ?Type $phpDocType, bool $tentativeReturnType) {
|
||||
public function __construct(bool $byRef, ?Type $type, ?Type $phpDocType, bool $tentativeReturnType, ?string $refcount) {
|
||||
$this->byRef = $byRef;
|
||||
$this->type = $type;
|
||||
$this->phpDocType = $phpDocType;
|
||||
$this->tentativeReturnType = $tentativeReturnType;
|
||||
$this->setTypes($type, $phpDocType, $tentativeReturnType);
|
||||
$this->setRefcount($refcount);
|
||||
}
|
||||
|
||||
public function equals(ReturnInfo $other): bool {
|
||||
public function equalsApartFromPhpDocAndRefcount(ReturnInfo $other): bool {
|
||||
return $this->byRef === $other->byRef
|
||||
&& Type::equals($this->type, $other->type)
|
||||
&& $this->tentativeReturnType === $other->tentativeReturnType;
|
||||
|
@ -644,6 +865,42 @@ class ReturnInfo {
|
|||
public function getMethodSynopsisType(): ?Type {
|
||||
return $this->type ?? $this->phpDocType;
|
||||
}
|
||||
|
||||
private function setTypes(?Type $type, ?Type $phpDocType, bool $tentativeReturnType): void
|
||||
{
|
||||
if ($phpDocType !== null && Type::equals($type, $phpDocType)) {
|
||||
throw new Exception('PHPDoc return type "' . $phpDocType->__toString() . '" is unnecessary');
|
||||
}
|
||||
|
||||
$this->type = $type;
|
||||
$this->phpDocType = $phpDocType;
|
||||
$this->tentativeReturnType = $tentativeReturnType;
|
||||
}
|
||||
|
||||
private function setRefcount(?string $refcount): void
|
||||
{
|
||||
$type = $this->phpDocType ?? $this->type;
|
||||
$isScalarType = $type !== null && $type->isScalar();
|
||||
|
||||
if ($refcount === null) {
|
||||
$this->refcount = $isScalarType ? self::REFCOUNT_0 : self::REFCOUNT_N;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in_array($refcount, ReturnInfo::REFCOUNTS, true)) {
|
||||
throw new Exception("@refcount must have one of the following values: \"0\", \"1\", \"N\", $refcount given");
|
||||
}
|
||||
|
||||
if ($isScalarType && $refcount !== self::REFCOUNT_0) {
|
||||
throw new Exception('A scalar return type of "' . $type->__toString() . '" must have a refcount of "' . self::REFCOUNT_0 . '"');
|
||||
}
|
||||
|
||||
if (!$isScalarType && $refcount === self::REFCOUNT_0) {
|
||||
throw new Exception('A non-scalar return type of "' . $type->__toString() . '" cannot have a refcount of "' . self::REFCOUNT_0 . '"');
|
||||
}
|
||||
|
||||
$this->refcount = $refcount;
|
||||
}
|
||||
}
|
||||
|
||||
class FuncInfo {
|
||||
|
@ -752,7 +1009,7 @@ class FuncInfo {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function equalsApartFromName(FuncInfo $other): bool {
|
||||
public function equalsApartFromNameAndRefcount(FuncInfo $other): bool {
|
||||
if (count($this->args) !== count($other->args)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -763,7 +1020,7 @@ class FuncInfo {
|
|||
}
|
||||
}
|
||||
|
||||
return $this->return->equals($other->return)
|
||||
return $this->return->equalsApartFromPhpDocAndRefcount($other->return)
|
||||
&& $this->numRequiredArgs === $other->numRequiredArgs
|
||||
&& $this->cond === $other->cond;
|
||||
}
|
||||
|
@ -860,6 +1117,27 @@ class FuncInfo {
|
|||
}
|
||||
}
|
||||
|
||||
public function getOptimizerInfo(): ?string {
|
||||
if ($this->isMethod()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->alias !== null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->return->refcount !== ReturnInfo::REFCOUNT_1 && $this->return->phpDocType === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$type = $this->return->phpDocType ?? $this->return->type;
|
||||
if ($type === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return " F" . $this->return->refcount . '("' . $this->name->__toString() . '", ' . $type->toOptimizerTypeMask() . "),\n";
|
||||
}
|
||||
|
||||
public function discardInfoForOldPhpVersions(): void {
|
||||
$this->return->type = null;
|
||||
foreach ($this->args as $arg) {
|
||||
|
@ -1733,12 +2011,12 @@ class DocCommentTag {
|
|||
$matches = [];
|
||||
|
||||
if ($this->name === "param") {
|
||||
preg_match('/^\s*([\w\|\\\\\[\]]+)\s*\$\w+.*$/', $value, $matches);
|
||||
preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)\s*\$\w+.*$/', $value, $matches);
|
||||
} elseif ($this->name === "return") {
|
||||
preg_match('/^\s*([\w\|\\\\\[\]]+)(\s+|$)/', $value, $matches);
|
||||
preg_match('/^\s*([\w\|\\\\\[\]<>, ]+)(\s+|$)/', $value, $matches);
|
||||
}
|
||||
|
||||
if (isset($matches[1]) === false) {
|
||||
if (!isset($matches[1])) {
|
||||
throw new Exception("@$this->name doesn't contain a type or has an invalid format \"$value\"");
|
||||
}
|
||||
|
||||
|
@ -1759,7 +2037,7 @@ class DocCommentTag {
|
|||
preg_match('/^\s*\$(\w+).*$/', $value, $matches);
|
||||
}
|
||||
|
||||
if (isset($matches[1]) === false) {
|
||||
if (!isset($matches[1])) {
|
||||
throw new Exception("@$this->name doesn't contain a variable name or has an invalid format \"$value\"");
|
||||
}
|
||||
|
||||
|
@ -1799,6 +2077,7 @@ function parseFunctionLike(
|
|||
$docReturnType = null;
|
||||
$tentativeReturnType = false;
|
||||
$docParamTypes = [];
|
||||
$refcount = null;
|
||||
|
||||
if ($comment) {
|
||||
$tags = parseDocComment($comment);
|
||||
|
@ -1827,6 +2106,8 @@ function parseFunctionLike(
|
|||
$docReturnType = $tag->getType();
|
||||
} else if ($tag->name === 'param') {
|
||||
$docParamTypes[$tag->getVariableName()] = $tag->getType();
|
||||
} else if ($tag->name === 'refcount') {
|
||||
$refcount = $tag->getValue();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1883,7 +2164,7 @@ function parseFunctionLike(
|
|||
$sendBy,
|
||||
$param->variadic,
|
||||
$type,
|
||||
isset($docParamTypes[$varName]) ? Type::fromPhpDoc($docParamTypes[$varName]) : null,
|
||||
isset($docParamTypes[$varName]) ? Type::fromString($docParamTypes[$varName]) : null,
|
||||
$param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null
|
||||
);
|
||||
if (!$param->default && !$param->variadic) {
|
||||
|
@ -1903,8 +2184,9 @@ function parseFunctionLike(
|
|||
$return = new ReturnInfo(
|
||||
$func->returnsByRef(),
|
||||
$returnType ? Type::fromNode($returnType) : null,
|
||||
$docReturnType ? Type::fromPhpDoc($docReturnType) : null,
|
||||
$tentativeReturnType
|
||||
$docReturnType ? Type::fromString($docReturnType) : null,
|
||||
$tentativeReturnType,
|
||||
$refcount
|
||||
);
|
||||
|
||||
return new FuncInfo(
|
||||
|
@ -2302,7 +2584,7 @@ function funcInfoToCode(FuncInfo $funcInfo): string {
|
|||
/** @param FuncInfo[] $generatedFuncInfos */
|
||||
function findEquivalentFuncInfo(array $generatedFuncInfos, FuncInfo $funcInfo): ?FuncInfo {
|
||||
foreach ($generatedFuncInfos as $generatedFuncInfo) {
|
||||
if ($generatedFuncInfo->equalsApartFromName($funcInfo)) {
|
||||
if ($generatedFuncInfo->equalsApartFromNameAndRefcount($funcInfo)) {
|
||||
return $generatedFuncInfo;
|
||||
}
|
||||
}
|
||||
|
@ -2416,6 +2698,22 @@ function generateFunctionEntries(?Name $className, array $funcInfos): string {
|
|||
return $code;
|
||||
}
|
||||
|
||||
/** @param FuncInfo[] $funcInfos */
|
||||
function generateOptimizerInfo(array $funcInfos): string {
|
||||
|
||||
$code = "/* This is a generated file, edit the .stub.php files instead. */\n\n";
|
||||
|
||||
$code .= "static const func_info_t func_infos[] = {\n";
|
||||
|
||||
$code .= generateCodeWithConditions($funcInfos, "", function (FuncInfo $funcInfo) {
|
||||
return $funcInfo->getOptimizerInfo();
|
||||
});
|
||||
|
||||
$code .= "};\n";
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassInfo[] $classMap
|
||||
* @return array<string, string>
|
||||
|
@ -2433,7 +2731,6 @@ function generateClassSynopses(array $classMap): array {
|
|||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param ClassInfo[] $classMap
|
||||
* @return array<string, string>
|
||||
|
@ -2812,7 +3109,7 @@ $options = getopt(
|
|||
"fh",
|
||||
[
|
||||
"force-regeneration", "parameter-stats", "help", "verify", "generate-classsynopses", "replace-classsynopses",
|
||||
"generate-methodsynopses", "replace-methodsynopses"
|
||||
"generate-methodsynopses", "replace-methodsynopses", "generate-optimizer-info"
|
||||
],
|
||||
$optind
|
||||
);
|
||||
|
@ -2824,8 +3121,9 @@ $generateClassSynopses = isset($options["generate-classsynopses"]);
|
|||
$replaceClassSynopses = isset($options["replace-classsynopses"]);
|
||||
$generateMethodSynopses = isset($options["generate-methodsynopses"]);
|
||||
$replaceMethodSynopses = isset($options["replace-methodsynopses"]);
|
||||
$generateOptimizerInfo = isset($options["generate-optimizer-info"]);
|
||||
$context->forceRegeneration = isset($options["f"]) || isset($options["force-regeneration"]);
|
||||
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify || $generateClassSynopses || $replaceClassSynopses || $generateMethodSynopses || $replaceMethodSynopses;
|
||||
$context->forceParse = $context->forceRegeneration || $printParameterStats || $verify || $generateClassSynopses || $generateOptimizerInfo || $replaceClassSynopses || $generateMethodSynopses || $replaceMethodSynopses;
|
||||
|
||||
$targetSynopses = $argv[$argc - 1] ?? null;
|
||||
if ($replaceClassSynopses && $targetSynopses === null) {
|
||||
|
@ -2961,13 +3259,22 @@ if ($verify) {
|
|||
$aliasArgs, $aliasedArgs
|
||||
);
|
||||
|
||||
$aliasedReturn = $aliasedFunc->return;
|
||||
$aliasReturn = $aliasFunc->return;
|
||||
|
||||
if (!$aliasedFunc->name->isConstructor() && !$aliasFunc->name->isConstructor()) {
|
||||
$aliasedReturnType = $aliasedFunc->return->type ?? $aliasedFunc->return->phpDocType;
|
||||
$aliasReturnType = $aliasFunc->return->type ?? $aliasFunc->return->phpDocType;
|
||||
$aliasedReturnType = $aliasedReturn->type ?? $aliasedReturn->phpDocType;
|
||||
$aliasReturnType = $aliasReturn->type ?? $aliasReturn->phpDocType;
|
||||
if ($aliasReturnType != $aliasedReturnType) {
|
||||
$errors[] = "{$aliasFunc->name}() and {$aliasedFunc->name}() must have the same return type";
|
||||
}
|
||||
}
|
||||
|
||||
$aliasedPhpDocReturnType = $aliasedReturn->phpDocType;
|
||||
$aliasPhpDocReturnType = $aliasReturn->phpDocType;
|
||||
if ($aliasedPhpDocReturnType != $aliasPhpDocReturnType && $aliasedPhpDocReturnType != $aliasReturn->type && $aliasPhpDocReturnType != $aliasedReturn->type) {
|
||||
$errors[] = "{$aliasFunc->name}() and {$aliasedFunc->name}() must have the same PHPDoc return type";
|
||||
}
|
||||
}
|
||||
|
||||
echo implode("\n", $errors);
|
||||
|
@ -3004,7 +3311,6 @@ if ($replaceClassSynopses) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if ($generateMethodSynopses) {
|
||||
$methodSynopsesDirectory = getcwd() . "/methodsynopses";
|
||||
|
||||
|
@ -3031,3 +3337,12 @@ if ($replaceMethodSynopses) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($generateOptimizerInfo) {
|
||||
$filename = dirname(__FILE__, 2) . "/Zend/Optimizer/zend_func_infos.h";
|
||||
$optimizerInfo = generateOptimizerInfo($funcMap);
|
||||
|
||||
if (file_put_contents($filename, $optimizerInfo)) {
|
||||
echo "Saved $filename\n";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -401,7 +401,10 @@ namespace {
|
|||
|
||||
function pg_get_pid(PgSql\Connection $connection): int {}
|
||||
|
||||
/** @return resource|false */
|
||||
/**
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function pg_socket(PgSql\Connection $connection) {}
|
||||
|
||||
function pg_consume_input(PgSql\Connection $connection): bool {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 37814767f8290b717a4facbdf55ef3bfc1fc24c8 */
|
||||
* Stub hash: 09b927fbe51265aa3895c6fadbbe66eb3087d4df */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_pg_connect, 0, 1, PgSql\\Connection, MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(0, connection_string, IS_STRING, 0)
|
||||
|
|
|
@ -288,6 +288,10 @@ function sleep(int $seconds): int {}
|
|||
function usleep(int $microseconds): void {}
|
||||
|
||||
#if HAVE_NANOSLEEP
|
||||
/**
|
||||
* @return array<string, int>|bool
|
||||
* @refcount 1
|
||||
*/
|
||||
function time_nanosleep(int $seconds, int $nanoseconds): array|bool {}
|
||||
|
||||
function time_sleep_until(float $timestamp): bool {}
|
||||
|
@ -421,6 +425,8 @@ function checkdnsrr(string $hostname, string $type = "MX"): bool {}
|
|||
/**
|
||||
* @param array $authoritative_name_servers
|
||||
* @param array $additional_records
|
||||
* @return array<int, array>|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function dns_get_record(string $hostname, int $type = DNS_ANY, &$authoritative_name_servers = null, &$additional_records = null, bool $raw = false): array|false {}
|
||||
|
||||
|
@ -772,7 +778,10 @@ function get_meta_tags(string $filename, bool $use_include_path = false): array|
|
|||
/** @param resource $handle */
|
||||
function pclose($handle): int {}
|
||||
|
||||
/** @return resource|false */
|
||||
/**
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function popen(string $command, string $mode) {}
|
||||
|
||||
/** @param resource|null $context */
|
||||
|
@ -804,6 +813,7 @@ function fread($stream, int $length): string|false {}
|
|||
/**
|
||||
* @param resource|null $context
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function fopen(string $filename, string $mode, bool $use_include_path = false, $context = null) {}
|
||||
|
||||
|
@ -854,7 +864,10 @@ function copy(string $from, string $to, $context = null): bool {}
|
|||
|
||||
function tempnam(string $directory, string $prefix): string|false {}
|
||||
|
||||
/** @return resource|false */
|
||||
/**
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function tmpfile() {}
|
||||
|
||||
/** @param resource|null $context */
|
||||
|
@ -975,6 +988,7 @@ function vfprintf($stream, string $format, array $values): int {}
|
|||
* @param int $error_code
|
||||
* @param string $error_message
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function fsockopen(string $hostname, int $port = -1, &$error_code = null, &$error_message = null, ?float $timeout = null) {}
|
||||
|
||||
|
@ -1165,6 +1179,7 @@ function password_algos(): array {}
|
|||
/**
|
||||
* @param array $pipes
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function proc_open(array|string $command, array $descriptor_spec, &$pipes, ?string $cwd = null, ?array $env_vars = null, ?array $options = null) {}
|
||||
|
||||
|
@ -1214,7 +1229,10 @@ function soundex(string $string): string {}
|
|||
|
||||
function stream_select(?array &$read, ?array &$write, ?array &$except, ?int $seconds, ?int $microseconds = null): int|false {}
|
||||
|
||||
/** @return resource */
|
||||
/**
|
||||
* @return resource
|
||||
* @refcount 1
|
||||
*/
|
||||
function stream_context_create(?array $options = null, ?array $params = null) {}
|
||||
|
||||
/** @param resource $context */
|
||||
|
@ -1255,6 +1273,7 @@ function stream_filter_remove($stream_filter): bool {}
|
|||
* @param string $error_message
|
||||
* @param resource|null $context
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function stream_socket_client(string $address, &$error_code = null, &$error_message = null, ?float $timeout = null, int $flags = STREAM_CLIENT_CONNECT, $context = null) {}
|
||||
|
||||
|
@ -1263,14 +1282,15 @@ function stream_socket_client(string $address, &$error_code = null, &$error_mess
|
|||
* @param string $error_message
|
||||
* @param resource|null $context
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function stream_socket_server(string $address, &$error_code = null, &$error_message = null, int $flags = STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context = null) {}
|
||||
|
||||
/**
|
||||
* @param resource $socket
|
||||
* @param float $timeout
|
||||
* @param string $peer_name
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function stream_socket_accept($socket, ?float $timeout = null, &$peer_name = null) {}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 82d7b69362e6dc0ccd8b7cb953ec0bdcb494137d */
|
||||
* Stub hash: a7e7f1f40e8ea4f8a532bce27b4841329a5a9663 */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
|
||||
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
||||
|
|
|
@ -24,7 +24,10 @@ function zlib_get_coding_type(): string|false {}
|
|||
|
||||
function gzfile(string $filename, int $use_include_path = 0): array|false {}
|
||||
|
||||
/** @return resource|false */
|
||||
/**
|
||||
* @return resource|false
|
||||
* @refcount 1
|
||||
*/
|
||||
function gzopen(string $filename, string $mode, int $use_include_path = 0) {}
|
||||
|
||||
function readgzfile(string $filename, int $use_include_path = 0): int|false {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* This is a generated file, edit the .stub.php file instead.
|
||||
* Stub hash: 2e3212e4cbb2fdeb5fc1342b19590bc89ae5d31a */
|
||||
* Stub hash: 89215fe1b85a38feee3926e25e9b8eac2365c4cb */
|
||||
|
||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_ob_gzhandler, 0, 2, MAY_BE_STRING|MAY_BE_FALSE)
|
||||
ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue