diff --git a/.gitattributes b/.gitattributes index de5a88e7..caf0fa86 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,7 @@ .github export-ignore apigen export-ignore +benchmarks export-ignore phpcs.xml export-ignore doc export-ignore tests export-ignore @@ -17,3 +18,4 @@ Makefile export-ignore phpstan-baseline.neon export-ignore phpstan.neon export-ignore phpunit.xml export-ignore +tally.php export-ignore diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml new file mode 100644 index 00000000..4895f1f5 --- /dev/null +++ b/.github/workflows/benchmarks.yml @@ -0,0 +1,57 @@ +# https://help.github.com/en/categories/automating-your-workflow-with-github-actions + +name: "Benchmarks" + +on: + pull_request: + push: + branches: + - "2.4.x" + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + benchmarks: + name: "Benchmarks" + # Tally's counts depend on the system libraries and the PHP build, so both stay fixed: + # a new image or PHP release means accepting new numbers + runs-on: "ubuntu-24.04" + + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@46b06cea07f9e64621fdf066ba77ac6915163d43 # v2.22.3 + with: + egress-policy: audit + + - name: "Checkout" + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + + - name: "Install PHP" + uses: "shivammathur/setup-php@eb7c497e18156a6bbabfef1d3a82760b9eda3962" # v2 + with: + coverage: "none" + php-version: "8.5" + extensions: "posix" + + - name: "Install dependencies" + run: "composer install --no-interaction --no-progress" + + - name: "Install Tally" + run: "make bench-install" + + - name: "Run the benchmarks" + run: "php tools/tally/vendor/bin/tally run --output=tmp/tally-results" + + - name: "Upload the results" + if: always() + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: "tally-results" + path: "tmp/tally-results" diff --git a/.gitignore b/.gitignore index 24aa3636..8e342d5f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /composer.lock .phpunit.result.cache /.amp/portals/* +/tools/tally/vendor diff --git a/CLAUDE.md b/CLAUDE.md index ddcdd0f2..6890deee 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -198,6 +198,7 @@ make check - `make lint` - Check PHP syntax only - `make cs` - Check code style only - `make phpstan-generate-baseline` - Generate PHPStan baseline (use sparingly) +- `make bench-install`, then `make bench` - Count the benchmarks in `benchmarks/` with [Tally](https://github.com/phpstan/tally) (needs PHP 8.2 on Linux). They cover parsing large and typical PHPDocs. Take their expected numbers from the Benchmarks workflow, not from a local run: a benchmark without numbers gets a patch in the job's output ## Workflow Summary diff --git a/Makefile b/Makefile index 40cf4820..b4384640 100644 --- a/Makefile +++ b/Makefile @@ -45,3 +45,16 @@ phpstan-generate-baseline: .PHONY: grammars-install grammars-install: composer install --no-interaction --working-dir tools/phplrt + +# --------------------------------------------------------------------------- +# The benchmarks +# --------------------------------------------------------------------------- + +# Tally is a development dependency of its own too, because it needs PHP 8.2. +.PHONY: bench-install +bench-install: + composer install --no-interaction --working-dir tools/tally + +.PHONY: bench +bench: + php tools/tally/vendor/bin/tally run diff --git a/benchmarks/LexerBench.php b/benchmarks/LexerBench.php new file mode 100644 index 00000000..aa800a00 --- /dev/null +++ b/benchmarks/LexerBench.php @@ -0,0 +1,39 @@ + */ + private array $phpDocs; + + #[Before] + public function prepare(): void + { + $this->lexer = new Lexer(new ParserConfig(['lines' => true])); + $this->phpDocs = require __DIR__ . '/data/vendor-docblocks.php'; + } + + #[Warmup(1)] + #[Expected(instructions: '25.27M', cycles: '26.59M', memory: '108.0KiB')] + public function benchTokenizeTypicalPhpDocs(): void + { + foreach ($this->phpDocs as $phpDoc) { + $this->lexer->tokenize($phpDoc); + } + } + +} diff --git a/benchmarks/SymfonyConfigReferenceBench.php b/benchmarks/SymfonyConfigReferenceBench.php new file mode 100644 index 00000000..91c2d756 --- /dev/null +++ b/benchmarks/SymfonyConfigReferenceBench.php @@ -0,0 +1,50 @@ + */ + private array $phpDocs; + + #[Before] + public function prepare(): void + { + $config = new ParserConfig(['lines' => true]); + $constExprParser = new ConstExprParser($config); + $this->lexer = new Lexer($config); + $this->phpDocParser = new PhpDocParser($config, new TypeParser($config, $constExprParser), $constExprParser); + $this->phpDocs = require __DIR__ . '/data/symfony-config-reference.php'; + } + + #[Warmup(1)] + #[Expected(instructions: '98.66M', cycles: '112.5M', memory: '4.123MiB')] + public function benchParse(): void + { + foreach ($this->phpDocs as $phpDoc) { + $this->phpDocParser->parse(new TokenIterator($this->lexer->tokenize($phpDoc))); + } + } + +} diff --git a/benchmarks/data/symfony-config-reference.php b/benchmarks/data/symfony-config-reference.php new file mode 100644 index 00000000..7b424f88 --- /dev/null +++ b/benchmarks/data/symfony-config-reference.php @@ -0,0 +1,815 @@ + '/** + * This class provides array-shapes for configuring the services and bundles of an application. + * + * Services declared with the config() method below are autowired and autoconfigured by default. + * + * This is for apps only. Bundles SHOULD NOT use it. + * + * Example: + * + * ```php + * // config/services.php + * namespace Symfony\\Component\\DependencyInjection\\Loader\\Configurator; + * + * return App::config([ + * \'services\' => [ + * \'App\\\\\' => [ + * \'resource\' => \'../src/\', + * ], + * ], + * ]); + * ``` + * + * @psalm-type ImportsConfig = list + * @psalm-type ParametersConfig = array|Param|null>|Param|null> + * @psalm-type ArgumentsType = list|array + * @psalm-type CallType = array|array{0:string, 1?:ArgumentsType, 2?:bool}|array{method:string, arguments?:ArgumentsType, returns_clone?:bool} + * @psalm-type TagsType = list>> // arrays inside the list must have only one element, with the tag name as the key + * @psalm-type CallbackType = string|array{0:string|ReferenceConfigurator,1:string}|\\Closure|ReferenceConfigurator + * @psalm-type DeprecationType = array{package: string, version: string, message?: string} + * @psalm-type DefaultsType = array{ + * public?: bool, + * tags?: TagsType, + * resource_tags?: TagsType, + * autowire?: bool, + * autoconfigure?: bool, + * bind?: array, + * } + * @psalm-type InstanceofType = array{ + * shared?: bool, + * lazy?: bool|string, + * public?: bool, + * properties?: array, + * configurator?: CallbackType, + * calls?: list, + * tags?: TagsType, + * resource_tags?: TagsType, + * autowire?: bool, + * bind?: array, + * constructor?: string, + * } + * @psalm-type DefinitionType = array{ + * class?: string, + * file?: string, + * parent?: string, + * shared?: bool, + * synthetic?: bool, + * lazy?: bool|string, + * public?: bool, + * abstract?: bool, + * deprecated?: DeprecationType, + * factory?: CallbackType, + * configurator?: CallbackType, + * arguments?: ArgumentsType, + * properties?: array, + * calls?: list, + * tags?: TagsType, + * resource_tags?: TagsType, + * decorates?: string, + * decoration_inner_name?: string, + * decoration_priority?: int, + * decoration_on_invalid?: \'exception\'|\'ignore\'|null, + * autowire?: bool, + * autoconfigure?: bool, + * bind?: array, + * constructor?: string, + * from_callable?: CallbackType, + * } + * @psalm-type AliasType = string|array{ + * alias: string, + * public?: bool, + * deprecated?: DeprecationType, + * } + * @psalm-type PrototypeType = array{ + * resource: string, + * namespace?: string, + * exclude?: string|list, + * parent?: string, + * shared?: bool, + * lazy?: bool|string, + * public?: bool, + * abstract?: bool, + * deprecated?: DeprecationType, + * factory?: CallbackType, + * arguments?: ArgumentsType, + * properties?: array, + * configurator?: CallbackType, + * calls?: list, + * tags?: TagsType, + * resource_tags?: TagsType, + * autowire?: bool, + * autoconfigure?: bool, + * bind?: array, + * constructor?: string, + * } + * @psalm-type StackType = array{ + * stack: list>, + * public?: bool, + * deprecated?: DeprecationType, + * } + * @psalm-type ServicesConfig = array{ + * _defaults?: DefaultsType, + * _instanceof?: array, + * ... + * } + * @psalm-type ExtensionType = array + * @psalm-type FrameworkConfig = array{ + * secret?: scalar|Param|null, + * http_method_override?: bool|Param, // Set true to enable support for the \'_method\' request parameter to determine the intended HTTP method on POST requests. // Default: false + * allowed_http_method_override?: null|list, + * trust_x_sendfile_type_header?: scalar|Param|null, // Set true to enable support for xsendfile in binary file responses. // Default: "%env(bool:default::SYMFONY_TRUST_X_SENDFILE_TYPE_HEADER)%" + * ide?: scalar|Param|null, // Default: "%env(default::SYMFONY_IDE)%" + * test?: bool|Param, + * default_locale?: scalar|Param|null, // Default: "en" + * set_locale_from_accept_language?: bool|Param, // Whether to use the Accept-Language HTTP header to set the Request locale (only when the "_locale" request attribute is not passed). // Default: false + * set_content_language_from_locale?: bool|Param, // Whether to set the Content-Language HTTP header on the Response using the Request locale. // Default: false + * enabled_locales?: list, + * trusted_hosts?: Param|string|list, + * trusted_proxies?: mixed, // Default: ["%env(default::SYMFONY_TRUSTED_PROXIES)%"] + * trusted_headers?: Param|string|list, + * error_controller?: scalar|Param|null, // Default: "error_controller" + * handle_all_throwables?: bool|Param, // HttpKernel will handle all kinds of \\Throwable. // Default: true + * csrf_protection?: bool|array{ + * enabled?: scalar|Param|null, // Default: null + * stateless_token_ids?: list, + * check_header?: scalar|Param|null, // Whether to check the CSRF token in a header in addition to a cookie when using stateless protection. // Default: false + * cookie_name?: scalar|Param|null, // The name of the cookie to use when using stateless protection. // Default: "csrf-token" + * }, + * form?: bool|array{ // Form configuration + * enabled?: bool|Param, // Default: false + * csrf_protection?: bool|array{ + * enabled?: scalar|Param|null, // Default: null + * token_id?: scalar|Param|null, // Default: null + * field_name?: scalar|Param|null, // Default: "_token" + * field_attr?: array, + * }, + * }, + * http_cache?: bool|array{ // HTTP cache configuration + * enabled?: bool|Param, // Default: false + * debug?: bool|Param, // Default: "%kernel.debug%" + * trace_level?: "none"|"short"|"full"|Param, + * trace_header?: scalar|Param|null, + * default_ttl?: int|Param, + * private_headers?: list, + * skip_response_headers?: list, + * allow_reload?: bool|Param, + * allow_revalidate?: bool|Param, + * stale_while_revalidate?: int|Param, + * stale_if_error?: int|Param, + * terminate_on_cache_hit?: bool|Param, + * }, + * esi?: bool|array{ // ESI configuration + * enabled?: bool|Param, // Default: false + * }, + * ssi?: bool|array{ // SSI configuration + * enabled?: bool|Param, // Default: false + * }, + * fragments?: bool|array{ // Fragments configuration + * enabled?: bool|Param, // Default: false + * hinclude_default_template?: scalar|Param|null, // Default: null + * path?: scalar|Param|null, // Default: "/_fragment" + * }, + * profiler?: bool|array{ // Profiler configuration + * enabled?: bool|Param, // Default: false + * collect?: bool|Param, // Default: true + * collect_parameter?: scalar|Param|null, // The name of the parameter to use to enable or disable collection on a per request basis. // Default: null + * only_exceptions?: bool|Param, // Default: false + * only_main_requests?: bool|Param, // Default: false + * dsn?: scalar|Param|null, // Default: "file:%kernel.cache_dir%/profiler" + * collect_serializer_data?: bool|Param, // Enables the serializer data collector and profiler panel. // Default: false + * }, + * workflows?: bool|array{ + * enabled?: bool|Param, // Default: false + * workflows?: array, + * definition_validators?: list, + * support_strategy?: scalar|Param|null, + * initial_marking?: \\BackedEnum|Param|string|list, + * events_to_dispatch?: null|list, + * places?: Param|string|list, + * }>, + * transitions?: list, + * to?: \\BackedEnum|Param|string|list, + * weight?: int|Param, // Default: 1 + * metadata?: array, + * }>, + * metadata?: array, + * }>, + * }, + * router?: bool|array{ // Router configuration + * enabled?: bool|Param, // Default: false + * resource?: scalar|Param|null, + * type?: scalar|Param|null, + * cache_dir?: scalar|Param|null, // Deprecated: Setting the "framework.router.cache_dir.cache_dir" configuration option is deprecated. It will be removed in version 8.0. // Default: "%kernel.build_dir%" + * default_uri?: scalar|Param|null, // The default URI used to generate URLs in a non-HTTP context. // Default: null + * http_port?: scalar|Param|null, // Default: 80 + * https_port?: scalar|Param|null, // Default: 443 + * strict_requirements?: scalar|Param|null, // set to true to throw an exception when a parameter does not match the requirements set to false to disable exceptions when a parameter does not match the requirements (and return null instead) set to null to disable parameter checks against requirements \'true\' is the preferred configuration in development mode, while \'false\' or \'null\' might be preferred in production // Default: true + * utf8?: bool|Param, // Default: true + * }, + * session?: bool|array{ // Session configuration + * enabled?: bool|Param, // Default: false + * storage_factory_id?: scalar|Param|null, // Default: "session.storage.factory.native" + * handler_id?: scalar|Param|null, // Defaults to using the native session handler, or to the native *file* session handler if "save_path" is not null. + * name?: scalar|Param|null, + * cookie_lifetime?: scalar|Param|null, + * cookie_path?: scalar|Param|null, + * cookie_domain?: scalar|Param|null, + * cookie_secure?: true|false|"auto"|Param, // Default: "auto" + * cookie_httponly?: bool|Param, // Default: true + * cookie_samesite?: null|"lax"|"strict"|"none"|Param, // Default: "lax" + * use_cookies?: bool|Param, + * gc_divisor?: scalar|Param|null, + * gc_probability?: scalar|Param|null, + * gc_maxlifetime?: scalar|Param|null, + * save_path?: scalar|Param|null, // Defaults to "%kernel.cache_dir%/sessions" if the "handler_id" option is not null. + * metadata_update_threshold?: int|Param, // Seconds to wait between 2 session metadata updates. // Default: 0 + * sid_length?: int|Param, // Deprecated: Setting the "framework.session.sid_length.sid_length" configuration option is deprecated. It will be removed in version 8.0. No alternative is provided as PHP 8.4 has deprecated the related option. + * sid_bits_per_character?: int|Param, // Deprecated: Setting the "framework.session.sid_bits_per_character.sid_bits_per_character" configuration option is deprecated. It will be removed in version 8.0. No alternative is provided as PHP 8.4 has deprecated the related option. + * }, + * request?: bool|array{ // Request configuration + * enabled?: bool|Param, // Default: false + * formats?: array>, + * }, + * assets?: bool|array{ // Assets configuration + * enabled?: bool|Param, // Default: false + * strict_mode?: bool|Param, // Throw an exception if an entry is missing from the manifest.json. // Default: false + * version_strategy?: scalar|Param|null, // Default: null + * version?: scalar|Param|null, // Default: null + * version_format?: scalar|Param|null, // Default: "%%s?%%s" + * json_manifest_path?: scalar|Param|null, // Default: null + * base_path?: scalar|Param|null, // Default: "" + * base_urls?: Param|string|list, + * packages?: array, + * }>, + * }, + * asset_mapper?: bool|array{ // Asset Mapper configuration + * enabled?: bool|Param, // Default: false + * paths?: Param|string|array, + * excluded_patterns?: list, + * exclude_dotfiles?: bool|Param, // If true, any files starting with "." will be excluded from the asset mapper. // Default: true + * server?: bool|Param, // If true, a "dev server" will return the assets from the public directory (true in "debug" mode only by default). // Default: true + * public_prefix?: scalar|Param|null, // The public path where the assets will be written to (and served from when "server" is true). // Default: "/assets/" + * missing_import_mode?: "strict"|"warn"|"ignore"|Param, // Behavior if an asset cannot be found when imported from JavaScript or CSS files - e.g. "import \'./non-existent.js\'". "strict" means an exception is thrown, "warn" means a warning is logged, "ignore" means the import is left as-is. // Default: "warn" + * extensions?: array, + * importmap_path?: scalar|Param|null, // The path of the importmap.php file. // Default: "%kernel.project_dir%/importmap.php" + * importmap_polyfill?: scalar|Param|null, // The importmap name that will be used to load the polyfill. Set to false to disable. // Default: "es-module-shims" + * importmap_script_attributes?: array, + * vendor_dir?: scalar|Param|null, // The directory to store JavaScript vendors. // Default: "%kernel.project_dir%/assets/vendor" + * precompress?: bool|array{ // Precompress assets with Brotli, Zstandard and gzip. + * enabled?: bool|Param, // Default: false + * formats?: list, + * extensions?: list, + * }, + * }, + * translator?: bool|array{ // Translator configuration + * enabled?: bool|Param, // Default: false + * fallbacks?: Param|string|list, + * logging?: bool|Param, // Default: false + * formatter?: scalar|Param|null, // Default: "translator.formatter.default" + * cache_dir?: scalar|Param|null, // Default: "%kernel.cache_dir%/translations" + * default_path?: scalar|Param|null, // The default path used to load translations. // Default: "%kernel.project_dir%/translations" + * paths?: list, + * pseudo_localization?: bool|array{ + * enabled?: bool|Param, // Default: false + * accents?: bool|Param, // Default: true + * expansion_factor?: float|Param, // Default: 1.0 + * brackets?: bool|Param, // Default: true + * parse_html?: bool|Param, // Default: false + * localizable_html_attributes?: list, + * }, + * providers?: array, + * locales?: list, + * }>, + * globals?: array, + * domain?: string|Param, + * }>, + * }, + * validation?: bool|array{ // Validation configuration + * enabled?: bool|Param, // Default: false + * cache?: scalar|Param|null, // Deprecated: Setting the "framework.validation.cache.cache" configuration option is deprecated. It will be removed in version 8.0. + * enable_attributes?: bool|Param, // Default: true + * static_method?: Param|string|list, + * translation_domain?: scalar|Param|null, // Default: "validators" + * email_validation_mode?: "html5"|"html5-allow-no-tld"|"strict"|"loose"|Param, // Default: "html5" + * mapping?: array{ + * paths?: list, + * }, + * not_compromised_password?: bool|array{ + * enabled?: bool|Param, // When disabled, compromised passwords will be accepted as valid. // Default: true + * endpoint?: scalar|Param|null, // API endpoint for the NotCompromisedPassword Validator. // Default: null + * }, + * disable_translation?: bool|Param, // Default: false + * auto_mapping?: array, + * }>, + * }, + * annotations?: bool|array{ + * enabled?: bool|Param, // Default: false + * }, + * serializer?: bool|array{ // Serializer configuration + * enabled?: bool|Param, // Default: false + * enable_attributes?: bool|Param, // Default: true + * name_converter?: scalar|Param|null, + * circular_reference_handler?: scalar|Param|null, + * max_depth_handler?: scalar|Param|null, + * mapping?: array{ + * paths?: list, + * }, + * default_context?: array, + * named_serializers?: array, + * include_built_in_normalizers?: bool|Param, // Whether to include the built-in normalizers // Default: true + * include_built_in_encoders?: bool|Param, // Whether to include the built-in encoders // Default: true + * }>, + * }, + * property_access?: bool|array{ // Property access configuration + * enabled?: bool|Param, // Default: false + * magic_call?: bool|Param, // Default: false + * magic_get?: bool|Param, // Default: true + * magic_set?: bool|Param, // Default: true + * throw_exception_on_invalid_index?: bool|Param, // Default: false + * throw_exception_on_invalid_property_path?: bool|Param, // Default: true + * }, + * type_info?: bool|array{ // Type info configuration + * enabled?: bool|Param, // Default: false + * aliases?: array, + * }, + * property_info?: bool|array{ // Property info configuration + * enabled?: bool|Param, // Default: false + * with_constructor_extractor?: bool|Param, // Registers the constructor extractor. + * }, + * cache?: array{ // Cache configuration + * prefix_seed?: scalar|Param|null, // Used to namespace cache keys when using several apps with the same shared backend. // Default: "_%kernel.project_dir%.%kernel.container_class%" + * app?: scalar|Param|null, // App related cache pools configuration. // Default: "cache.adapter.filesystem" + * system?: scalar|Param|null, // System related cache pools configuration. // Default: "cache.adapter.system" + * directory?: scalar|Param|null, // Default: "%kernel.share_dir%/pools/app" + * default_psr6_provider?: scalar|Param|null, + * default_redis_provider?: scalar|Param|null, // Default: "redis://localhost" + * default_valkey_provider?: scalar|Param|null, // Default: "valkey://localhost" + * default_memcached_provider?: scalar|Param|null, // Default: "memcached://localhost" + * default_doctrine_dbal_provider?: scalar|Param|null, // Default: "database_connection" + * default_pdo_provider?: scalar|Param|null, // Default: null + * pools?: array, + * tags?: scalar|Param|null, // Default: null + * public?: bool|Param, // Default: false + * default_lifetime?: scalar|Param|null, // Default lifetime of the pool. + * provider?: scalar|Param|null, // Overwrite the setting from the default provider for this adapter. + * early_expiration_message_bus?: scalar|Param|null, + * clearer?: scalar|Param|null, + * }>, + * }, + * php_errors?: array{ // PHP errors handling configuration + * log?: mixed, // Use the application logger instead of the PHP logger for logging PHP errors. // Default: true + * throw?: bool|Param, // Throw PHP errors as \\ErrorException instances. // Default: true + * }, + * exceptions?: array, + * web_link?: bool|array{ // Web links configuration + * enabled?: bool|Param, // Default: false + * }, + * lock?: Param|bool|string|array{ // Lock configuration + * enabled?: bool|Param, // Default: false + * resources?: Param|string|array>, + * }, + * semaphore?: Param|bool|string|array{ // Semaphore configuration + * enabled?: bool|Param, // Default: false + * resources?: Param|string|array, + * }, + * messenger?: bool|array{ // Messenger configuration + * enabled?: bool|Param, // Default: false + * routing?: array, + * }>, + * serializer?: array{ + * default_serializer?: scalar|Param|null, // Service id to use as the default serializer for the transports. // Default: "messenger.transport.native_php_serializer" + * symfony_serializer?: array{ + * format?: scalar|Param|null, // Serialization format for the messenger.transport.symfony_serializer service (which is not the serializer used by default). // Default: "json" + * context?: array, + * }, + * }, + * transports?: array, + * failure_transport?: scalar|Param|null, // Transport name to send failed messages to (after all retries have failed). // Default: null + * retry_strategy?: Param|string|array{ + * service?: scalar|Param|null, // Service id to override the retry strategy entirely. // Default: null + * max_retries?: int|Param, // Default: 3 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: this delay = (delay * (multiple ^ retries)). // Default: 2 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 + * jitter?: float|Param, // Randomness to apply to the delay (between 0 and 1). // Default: 0.1 + * }, + * rate_limiter?: scalar|Param|null, // Rate limiter name to use when processing messages. // Default: null + * }>, + * failure_transport?: scalar|Param|null, // Transport name to send failed messages to (after all retries have failed). // Default: null + * stop_worker_on_signals?: Param|int|string|list, + * default_bus?: scalar|Param|null, // Default: null + * buses?: array, + * }>, + * }>, + * }, + * scheduler?: bool|array{ // Scheduler configuration + * enabled?: bool|Param, // Default: false + * }, + * disallow_search_engine_index?: bool|Param, // Enabled by default when debug is enabled. // Default: true + * http_client?: bool|array{ // HTTP Client configuration + * enabled?: bool|Param, // Default: true + * max_host_connections?: int|Param, // The maximum number of connections to a single host. + * default_options?: array{ + * headers?: array, + * vars?: array, + * max_redirects?: int|Param, // The maximum number of redirects to follow. + * http_version?: scalar|Param|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. + * resolve?: array, + * proxy?: scalar|Param|null, // The URL of the proxy to pass requests through or null for automatic detection. + * no_proxy?: scalar|Param|null, // A comma separated list of hosts that do not require a proxy to be reached. + * timeout?: float|Param, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. + * max_duration?: float|Param, // The maximum execution time for the request+response as a whole. + * bindto?: scalar|Param|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. + * verify_peer?: bool|Param, // Indicates if the peer should be verified in a TLS context. + * verify_host?: bool|Param, // Indicates if the host should exist as a certificate common name. + * cafile?: scalar|Param|null, // A certificate authority file. + * capath?: scalar|Param|null, // A directory that contains multiple certificate authority files. + * local_cert?: scalar|Param|null, // A PEM formatted certificate file. + * local_pk?: scalar|Param|null, // A private key file. + * passphrase?: scalar|Param|null, // The passphrase used to encrypt the "local_pk" file. + * ciphers?: scalar|Param|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...) + * peer_fingerprint?: array{ // Associative array: hashing algorithm => hash(es). + * sha1?: mixed, + * pin-sha256?: mixed, + * md5?: mixed, + * }, + * crypto_method?: scalar|Param|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. + * extra?: array, + * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null + * caching?: bool|array{ // Caching configuration. + * enabled?: bool|Param, // Default: false + * cache_pool?: string|Param, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" + * shared?: bool|Param, // Indicates whether the cache is shared (public) or private. // Default: true + * max_ttl?: int|Param, // The maximum TTL (in seconds) allowed for cached responses. Null means no cap. // Default: null + * }, + * retry_failed?: bool|array{ + * enabled?: bool|Param, // Default: false + * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null + * http_codes?: Param|int|string|array, + * }>, + * max_retries?: int|Param, // Default: 3 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 + * jitter?: float|Param, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 + * }, + * }, + * mock_response_factory?: scalar|Param|null, // The id of the service that should generate mock responses. It should be either an invokable or an iterable. + * scoped_clients?: array, + * headers?: array, + * max_redirects?: int|Param, // The maximum number of redirects to follow. + * http_version?: scalar|Param|null, // The default HTTP version, typically 1.1 or 2.0, leave to null for the best version. + * resolve?: array, + * proxy?: scalar|Param|null, // The URL of the proxy to pass requests through or null for automatic detection. + * no_proxy?: scalar|Param|null, // A comma separated list of hosts that do not require a proxy to be reached. + * timeout?: float|Param, // The idle timeout, defaults to the "default_socket_timeout" ini parameter. + * max_duration?: float|Param, // The maximum execution time for the request+response as a whole. + * bindto?: scalar|Param|null, // A network interface name, IP address, a host name or a UNIX socket to bind to. + * verify_peer?: bool|Param, // Indicates if the peer should be verified in a TLS context. + * verify_host?: bool|Param, // Indicates if the host should exist as a certificate common name. + * cafile?: scalar|Param|null, // A certificate authority file. + * capath?: scalar|Param|null, // A directory that contains multiple certificate authority files. + * local_cert?: scalar|Param|null, // A PEM formatted certificate file. + * local_pk?: scalar|Param|null, // A private key file. + * passphrase?: scalar|Param|null, // The passphrase used to encrypt the "local_pk" file. + * ciphers?: scalar|Param|null, // A list of TLS ciphers separated by colons, commas or spaces (e.g. "RC3-SHA:TLS13-AES-128-GCM-SHA256"...). + * peer_fingerprint?: array{ // Associative array: hashing algorithm => hash(es). + * sha1?: mixed, + * pin-sha256?: mixed, + * md5?: mixed, + * }, + * crypto_method?: scalar|Param|null, // The minimum version of TLS to accept; must be one of STREAM_CRYPTO_METHOD_TLSv*_CLIENT constants. + * extra?: array, + * rate_limiter?: scalar|Param|null, // Rate limiter name to use for throttling requests. // Default: null + * caching?: bool|array{ // Caching configuration. + * enabled?: bool|Param, // Default: false + * cache_pool?: string|Param, // The taggable cache pool to use for storing the responses. // Default: "cache.http_client" + * shared?: bool|Param, // Indicates whether the cache is shared (public) or private. // Default: true + * max_ttl?: int|Param, // The maximum TTL (in seconds) allowed for cached responses. Null means no cap. // Default: null + * }, + * retry_failed?: bool|array{ + * enabled?: bool|Param, // Default: false + * retry_strategy?: scalar|Param|null, // service id to override the retry strategy. // Default: null + * http_codes?: Param|int|string|array, + * }>, + * max_retries?: int|Param, // Default: 3 + * delay?: int|Param, // Time in ms to delay (or the initial value when multiplier is used). // Default: 1000 + * multiplier?: float|Param, // If greater than 1, delay will grow exponentially for each retry: delay * (multiple ^ retries). // Default: 2 + * max_delay?: int|Param, // Max time in ms that a retry should ever be delayed (0 = infinite). // Default: 0 + * jitter?: float|Param, // Randomness in percent (between 0 and 1) to apply to the delay. // Default: 0.1 + * }, + * }>, + * }, + * mailer?: bool|array{ // Mailer configuration + * enabled?: bool|Param, // Default: false + * message_bus?: scalar|Param|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null + * dsn?: scalar|Param|null, // Default: null + * transports?: array, + * envelope?: array{ // Mailer Envelope configuration + * sender?: scalar|Param|null, + * recipients?: Param|string|list, + * allowed_recipients?: Param|string|list, + * }, + * headers?: array, + * dkim_signer?: bool|array{ // DKIM signer configuration + * enabled?: bool|Param, // Default: false + * key?: scalar|Param|null, // Key content, or path to key (in PEM format with the `file://` prefix) // Default: "" + * domain?: scalar|Param|null, // Default: "" + * select?: scalar|Param|null, // Default: "" + * passphrase?: scalar|Param|null, // The private key passphrase // Default: "" + * options?: array, + * }, + * smime_signer?: bool|array{ // S/MIME signer configuration + * enabled?: bool|Param, // Default: false + * key?: scalar|Param|null, // Path to key (in PEM format) // Default: "" + * certificate?: scalar|Param|null, // Path to certificate (in PEM format without the `file://` prefix) // Default: "" + * passphrase?: scalar|Param|null, // The private key passphrase // Default: null + * extra_certificates?: scalar|Param|null, // Default: null + * sign_options?: int|Param, // Default: null + * }, + * smime_encrypter?: bool|array{ // S/MIME encrypter configuration + * enabled?: bool|Param, // Default: false + * repository?: scalar|Param|null, // S/MIME certificate repository service. This service shall implement the `Symfony\\Component\\Mailer\\EventListener\\SmimeCertificateRepositoryInterface`. // Default: "" + * cipher?: int|Param, // A set of algorithms used to encrypt the message // Default: null + * }, + * }, + * secrets?: bool|array{ + * enabled?: bool|Param, // Default: true + * vault_directory?: scalar|Param|null, // Default: "%kernel.project_dir%/config/secrets/%kernel.runtime_environment%" + * local_dotenv_file?: scalar|Param|null, // Default: "%kernel.project_dir%/.env.%kernel.environment%.local" + * decryption_env_var?: scalar|Param|null, // Default: "base64:default::SYMFONY_DECRYPTION_SECRET" + * }, + * notifier?: bool|array{ // Notifier configuration + * enabled?: bool|Param, // Default: false + * message_bus?: scalar|Param|null, // The message bus to use. Defaults to the default bus if the Messenger component is installed. // Default: null + * chatter_transports?: array, + * texter_transports?: array, + * notification_on_failed_messages?: bool|Param, // Default: false + * channel_policy?: array>, + * admin_recipients?: list, + * }, + * rate_limiter?: bool|array{ // Rate limiter configuration + * enabled?: bool|Param, // Default: false + * limiters?: array, + * limit?: int|Param, // The maximum allowed hits in a fixed interval or burst. + * interval?: scalar|Param|null, // Configures the fixed interval if "policy" is set to "fixed_window" or "sliding_window". The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). + * rate?: array{ // Configures the fill rate if "policy" is set to "token_bucket". + * interval?: scalar|Param|null, // Configures the rate interval. The value must be a number followed by "second", "minute", "hour", "day", "week" or "month" (or their plural equivalent). + * amount?: int|Param, // Amount of tokens to add each interval. // Default: 1 + * }, + * }>, + * }, + * uid?: bool|array{ // Uid configuration + * enabled?: bool|Param, // Default: false + * default_uuid_version?: 7|6|4|1|Param, // Default: 7 + * name_based_uuid_version?: 5|3|Param, // Default: 5 + * name_based_uuid_namespace?: scalar|Param|null, + * time_based_uuid_version?: 7|6|1|Param, // Default: 7 + * time_based_uuid_node?: scalar|Param|null, + * }, + * html_sanitizer?: bool|array{ // HtmlSanitizer configuration + * enabled?: bool|Param, // Default: false + * sanitizers?: array, + * block_elements?: Param|string|list, + * drop_elements?: Param|string|list, + * allow_attributes?: array, + * drop_attributes?: array, + * force_attributes?: array>, + * force_https_urls?: bool|Param, // Transforms URLs using the HTTP scheme to use the HTTPS scheme instead. // Default: false + * allowed_link_schemes?: Param|string|list, + * allowed_link_hosts?: Param|null|string|list, + * allow_relative_links?: bool|Param, // Allows relative URLs to be used in links href attributes. // Default: false + * allowed_media_schemes?: Param|string|list, + * allowed_media_hosts?: Param|null|string|list, + * allow_relative_medias?: bool|Param, // Allows relative URLs to be used in media source attributes (img, audio, video, ...). // Default: false + * with_attribute_sanitizers?: Param|string|list, + * without_attribute_sanitizers?: Param|string|list, + * max_input_length?: int|Param, // The maximum length allowed for the sanitized input. // Default: 0 + * }>, + * }, + * webhook?: bool|array{ // Webhook configuration + * enabled?: bool|Param, // Default: false + * message_bus?: scalar|Param|null, // The message bus to use. // Default: "messenger.default_bus" + * routing?: array, + * }, + * remote_event?: bool|array{ // RemoteEvent configuration + * enabled?: bool|Param, // Default: false + * }, + * json_streamer?: bool|array{ // JSON streamer configuration + * enabled?: bool|Param, // Default: false + * }, + * } + * @psalm-type CmsigSealConfig = array{ + * index_name_prefix?: scalar|Param|null, // Default: "" + * schemas?: array, + * engines?: array, + * } + * @psalm-type MakerConfig = array{ + * root_namespace?: scalar|Param|null, // Default: "App" + * generate_final_classes?: bool|Param, // Default: true + * generate_final_entities?: bool|Param, // Default: false + * } + * @psalm-type ConfigType = array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * framework?: FrameworkConfig, + * cmsig_seal?: CmsigSealConfig, + * "when@dev"?: array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * framework?: FrameworkConfig, + * cmsig_seal?: CmsigSealConfig, + * maker?: MakerConfig, + * }, + * "when@prod"?: array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * framework?: FrameworkConfig, + * cmsig_seal?: CmsigSealConfig, + * }, + * "when@test"?: array{ + * imports?: ImportsConfig, + * parameters?: ParametersConfig, + * services?: ServicesConfig, + * framework?: FrameworkConfig, + * cmsig_seal?: CmsigSealConfig, + * }, + * ..., + * }> + * } + */', + 1 => '/** + * @param ConfigType $config + * + * @psalm-return ConfigType + */', + 2 => '/** @var ConfigType $config */', + 3 => '/** + * This class provides array-shapes for configuring the routes of an application. + * + * Example: + * + * ```php + * // config/routes.php + * namespace Symfony\\Component\\Routing\\Loader\\Configurator; + * + * return Routes::config([ + * \'controllers\' => [ + * \'resource\' => \'routing.controllers\', + * ], + * ]); + * ``` + * + * @psalm-type RouteConfig = array{ + * path: string|array, + * controller?: string, + * methods?: string|list, + * requirements?: array, + * defaults?: array, + * options?: array, + * host?: string|array, + * schemes?: string|list, + * condition?: string, + * locale?: string, + * format?: string, + * utf8?: bool, + * stateless?: bool, + * } + * @psalm-type ImportConfig = array{ + * resource: string, + * type?: string, + * exclude?: string|list, + * prefix?: string|array, + * name_prefix?: string, + * trailing_slash_on_root?: bool, + * controller?: string, + * methods?: string|list, + * requirements?: array, + * defaults?: array, + * options?: array, + * host?: string|array, + * schemes?: string|list, + * condition?: string, + * locale?: string, + * format?: string, + * utf8?: bool, + * stateless?: bool, + * } + * @psalm-type AliasConfig = array{ + * alias: string, + * deprecated?: array{package:string, version:string, message?:string}, + * } + * @psalm-type RoutesConfig = array{ + * "when@dev"?: array, + * "when@prod"?: array, + * "when@test"?: array, + * ... + * } + */', + 4 => '/** + * @param RoutesConfig $config + * + * @psalm-return RoutesConfig + */', +); diff --git a/benchmarks/data/vendor-docblocks.php b/benchmarks/data/vendor-docblocks.php new file mode 100644 index 00000000..9ed33bf8 --- /dev/null +++ b/benchmarks/data/vendor-docblocks.php @@ -0,0 +1,2115 @@ + '/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \\Composer\\Autoload\\ClassLoader(); + * + * // register classes with namespaces + * $loader->add(\'Symfony\\Component\', __DIR__.\'/component\'); + * $loader->add(\'Symfony\', __DIR__.\'/framework\'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\\Component + * namespace or one of its children (Symfony\\Component\\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */', + 1 => '/** @var bool */', + 2 => '/** + * @param array $classMap Class to filename map + * + * @return void + */', + 3 => '/** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */', + 4 => '/** + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to + * @internal + */', + 5 => '/** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */', + 6 => '/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */', + 7 => '/** + * Creates a new AnnotationException describing an required error of an attribute. + * + * @return AnnotationException + */', + 8 => '/** + * {@inheritDoc} + */', + 9 => '/** + * Parse a class or function for use statements. + * + * @param ReflectionClass|ReflectionFunction $reflection + * + * @psalm-return array a list with use statements in the form (Alias => FQN). + */', + 10 => '/** + * Proxies all methods to the delegate. + * + * @param mixed[] $args + * + * @return mixed + */', + 11 => '/** + * Targets as bitmask. + * + * @var int + */', + 12 => '/** + * Annotation that can be used to signal to the parser + * to check the available values during the parsing process. + * + * @Annotation + * @Attributes({ + * @Attribute("value", required = true, type = "array"), + * @Attribute("literal", required = false, type = "array") + * }) + */', + 13 => '/** + * Gets the annotations applied to a class. + * + * @param ReflectionClass $class The ReflectionClass of the class from which + * the class annotations should be read. + * + * @return array An array of Annotations. + */', + 14 => '/** + * Gets the next non whitespace and non comment token. + * + * @param bool $docCommentIsComment If TRUE then a doc comment is considered a comment and skipped. + * If FALSE then only whitespace and normal comments are skipped. + * + * @return mixed[]|string|null The token if exists, null otherwise. + */', + 15 => '/** + * Add a new annotation to the globally ignored annotation names with regard to exception handling. + */', + 16 => '/** + * {@inheritDoc} + */', + 17 => '/** + * Collects parsing metadata for a given class or function. + * + * @param ReflectionClass|ReflectionFunction $reflection + */', + 18 => '/** + * An array of default namespaces if operating in simple mode. + * + * @var string[] + */', + 19 => '/** + * Sets the default namespaces. + * + * @return void + * + * @throws RuntimeException + */', + 20 => '/** + * Collects parsing metadata for a given attribute. + * + * @param mixed[] $metadata + */', + 21 => '/** + * PlainValue ::= integer | string | float | boolean | Array | Annotation + * + * @return mixed + * + * @throws AnnotationException + * @throws ReflectionException + */', + 22 => '/** + * Whether the next token starts immediately, or if there were + * non-captured symbols before that + */', + 23 => '/** + * Trigger a deprecation for the given package and identifier when called from outside. + * + * "Outside" means we assume that $package is currently installed as a + * dependency and the caller is not a file in that package. When $package + * is installed as a root package then deprecations triggered from the + * tests folder are also considered "outside". + * + * This deprecation method assumes that you are using Composer to install + * the dependency and are using the default /vendor/ folder and not a + * Composer plugin to change the install location. The assumption is also + * that $package is the exact composer packge name. + * + * Compared to {@link trigger()} this method causes some overhead when + * deprecation tracking is enabled even during deduplication, because it + * needs to call {@link debug_backtrace()} + * + * @param float|int|string $args + */', + 24 => '/** + * @after + * @final since 1.2 + */', + 25 => '/** + * @phpstan-param ReflectionClass $reflectionClass + * + * @throws UnexpectedValueException + * + * @template T of object + */', + 26 => '/** + * @phpstan-param ReflectionClass $reflectionClass + * + * @template T of object + */', + 27 => '/** + * @deprecated Use the value, type or position property instead + * {@inheritDoc} + * + * @param O $offset + * + * @return mixed + * @psalm-return ( + * O is \'value\' + * ? V + * : ( + * O is \'type\' + * ? T|null + * : ( + * O is \'position\' + * ? int + * : mixed + * ) + * ) + * ) + * + * @template O of array-key + */', + 28 => '/** + * Composed regex for input parsing. + * + * @var non-empty-string|null + */', + 29 => '/** + * Checks if given value is identical to the given token. + * + * @param string $value + * @param int|string $token + * + * @return bool + */', + 30 => '/** + * @var callable + */', + 31 => '/** + * @final + */', + 32 => '/** + * Retrieves property by name from object and all its ancestors. + * + * @param object|string $object + * @param string $name + * + * @throws PropertyException + * @throws ReflectionException + * + * @return ReflectionProperty + */', + 33 => '/** + * {@inheritdoc} + */', + 34 => '/** + * @var string + */', + 35 => '/** + * Matches a property by its type. + * + * It is recommended to use {@see DeepCopy\\TypeFilter\\TypeFilter} instead, as it applies on all occurrences + * of given type in copied context (eg. array elements), not just on object properties. + * + * @final + */', + 36 => '/** + * @var bool + */', + 37 => '/** + * A PHP version, representing only the major and minor version components. + */', + 38 => '/** + * Check whether this is the host PHP version. + */', + 39 => '/** + * Whether this version supports unicode escape sequences in strings. + */', + 40 => '/** + * @internal + */', + 41 => '/** @var int Number of non-leaf states */', + 42 => '/** @var callable[] Semantic action callbacks */', + 43 => '/** @var int[] Token end position stack */', + 44 => '/** @return Stmt[]|null */', + 45 => '/** @param array $attributes */', + 46 => '/** + * @param Property|Param $node + */', + 47 => '/** + * Error handler that handles all errors by throwing them. + * + * This is the default strategy used by all components. + */', + 48 => '/** + * Gets all comments directly preceding this node. + * + * The comments are also available through the "comments" attribute. + * + * @return Comment[] + */', + 49 => '/** + * Gets the comment text. + * + * @return string The comment text (including comment delimiters like /*) + */', + 50 => '/** + * @return array{nodeType:string, text:mixed, line:mixed, filePos:mixed} + */', + 51 => '/** + * Normalizes a doc comment: Converts plain strings to PhpParser\\Comment\\Doc. + * + * @param Comment\\Doc|string $docComment The doc comment to normalize + * + * @return Comment\\Doc The normalized doc comment + */', + 52 => '/** + * Gets the token offset of the last token that is part of this node. + * + * The offset is an index into the array returned by Lexer::getTokens(). + * + * Requires the \'endTokenPos\' attribute to be enabled in the lexer (DISABLED by default). + * + * @return int Token end position (or -1 if not available) + */', + 53 => '/** + * Calculate diff (edit script) from $old to $new. + * + * @param T[] $old Original array + * @param T[] $new New array + * + * @return DiffElem[] Diff (edit script) + */', + 54 => '/** + * Whether the given position is immediately surrounded by braces. + * + * @param int $startPos Start position + * @param int $endPos End position + */', + 55 => '/** + * Get the code corresponding to a token offset range, optionally adjusted for indentation. + * + * @param int $from Token start position (inclusive) + * @param int $to Token end position (exclusive) + * @param int $indent By how much the code should be indented (can be negative as well) + * + * @return string Code corresponding to token range, adjusted for indentation + */', + 56 => '/** + * Get the name of the token. For single-char tokens this will be the token character. + * Otherwise it will be a T_* style name, or null if the token ID is unknown. + */', + 57 => '/** @var null|Node\\Name Name of extended class */', + 58 => '/** @var Name[][] Map of format [aliasType => [aliasName => originalName]] */', + 59 => '/** + * Get shortest representation of this fully-qualified name. + * + * @param string $name Fully-qualified name (without leading namespace separator) + * @param Stmt\\Use_::TYPE_* $type One of Stmt\\Use_::TYPE_* + * + * @return Name Shortest representation + */', + 60 => '/** @return mixed */', + 61 => '/** @param Token[] $tokens */', + 62 => '/** @var list Attribute arguments */', + 63 => '/** @var null|Expr|Stmt[] Hook body */', + 64 => '/** @var Expr Variable */', + 65 => '/** @var Node\\Stmt[] Statements */', + 66 => '/** @var Expr Expression */', + 67 => '/** @var Name|Expr Class name */', + 68 => '/** + * Constructs a pre increment node. + * + * @param Expr $var Variable + * @param array $attributes Additional attributes + */', + 69 => '/** + * Returns whether this call expression is a partial function application, i.e. whether its + * argument list contains one or more "?" placeholders or a "..." placeholder. First-class + * callables are a special case of partial function application, so this also returns true + * for them. + */', + 70 => '/** @var Identifier|Expr Method name */', + 71 => '/** + * Constructs a unary minus node. + * + * @param Expr $expr Expression + * @param array $attributes Additional attributes + */', + 72 => '/** + * Constructs a shell exec (backtick) node. + * + * @param (Expr|InterpolatedStringPart)[] $parts Interpolated string array + * @param array $attributes Additional attributes + */', + 73 => '/** + * Constructs a const fetch node. + * + * @param Name $name Constant name + * @param array $attributes Additional attributes + */', + 74 => '/** + * Constructs a boolean not node. + * + * @param Expr $expr Expression + * @param array $attributes Additional attributes + */', + 75 => '/** + * Constructs an print() node. + * + * @param Expr $expr Expression + * @param array $attributes Additional attributes + */', + 76 => '/** @var Expr Variable */', + 77 => '/** @var Expr Expression body */', + 78 => '/** + * Get identifier as string. + * + * @psalm-return non-empty-string + * @return string Identifier as string. + */', + 79 => '/** + * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\\Name) + * + * @return bool Whether the name is relative + */', + 80 => '/** + * @psalm-var non-empty-string + * @var string Name as string + */', + 81 => '/** + * Returns a string representation of the name itself, without taking the name type into + * account (e.g., not including a leading backslash for fully qualified names). + * + * @psalm-return non-empty-string + * @return string String representation + */', + 82 => '/** @var bool Whether to assign by reference */', + 83 => '/** @var null|Identifier|Name|ComplexType Type declaration */', + 84 => '/** + * Whether the property is final. + */', + 85 => '/** + * Constructs a declare node. + * + * @param DeclareItem[] $declares List of declares + * @param Node\\Stmt[]|null $stmts Statements + * @param array $attributes Additional attributes + */', + 86 => '/** @deprecated Use Modifiers::PROTECTED instead */', + 87 => '/** + * Constructs a class node. + * + * @param string|Node\\Identifier|null $name Name + * @param array{ + * flags?: int, + * extends?: Node\\Name|null, + * implements?: Node\\Name[], + * stmts?: Node\\Stmt[], + * attrGroups?: Node\\AttributeGroup[], + * } $subNodes Array of the following optional subnodes: + * \'flags\' => 0 : Flags + * \'extends\' => null : Name of extended class + * \'implements\' => array(): Names of implemented interfaces + * \'stmts\' => array(): Statements + * \'attrGroups\' => array(): PHP attribute groups + * @param array $attributes Additional attributes + */', + 88 => '/** + * Constructs a case node. + * + * @param null|Node\\Expr $cond Condition (null for default) + * @param Node\\Stmt[] $stmts Statements + * @param array $attributes Additional attributes + */', + 89 => '/** @var self::TYPE_* Type of alias */', + 90 => '/** @var int Modifiers */', + 91 => '/** @var Name Prefix for uses */', + 92 => '/** + * Constructs an else node. + * + * @param Node\\Stmt[] $stmts Statements + * @param array $attributes Additional attributes + */', + 93 => '/** @var Node\\Name|null Trait name */', + 94 => '/** @var Node\\Expr Condition */', + 95 => '/** + * Constructs a finally node. + * + * @param Node\\Stmt[] $stmts Statements + * @param array $attributes Additional attributes + */', + 96 => '/** @var Node\\Identifier|null Name */', + 97 => '/** @var Node\\Expr[] Variables to unset */', + 98 => '/** @var Node\\AttributeGroup[] PHP attribute groups */', + 99 => '/** + * Constructs an if node. + * + * @param Node\\Expr $cond Condition + * @param array{ + * stmts?: Node\\Stmt[], + * elseifs?: ElseIf_[], + * else?: Else_|null, + * } $subNodes Array of the following optional subnodes: + * \'stmts\' => array(): Statements + * \'elseifs\' => array(): Elseif clauses + * \'else\' => null : Else clause + * @param array $attributes Additional attributes + */', + 100 => '/** @var Node\\Param[] Parameters */', + 101 => '/** + * Whether the method is final. + */', + 102 => '/** + * Get the declared return type or null + * + * @return null|Identifier|Name|ComplexType + */', + 103 => '/** + * Constructs an alias (use) item node. + * + * @param Node\\Name $name Namespace/Class to alias + * @param null|string|Identifier $alias Alias + * @param Use_::TYPE_* $type Type of the use element (for mixed group use only) + * @param array $attributes Additional attributes + */', + 104 => '/** @var int Optional visibility flags */', + 105 => '/** @var int Number value */', + 106 => '/** + * Constructs a magic constant node. + * + * @param array $attributes Additional attributes + */', + 107 => '/** + * This is a base class for complex types, including nullable types and union types. + * + * It does not provide any shared behavior and exists only for type-checking purposes. + */', + 108 => '/** @param (Expr|Node\\InterpolatedStringPart)[] $parts */', + 109 => '/** + * Creates a trait builder. + * + * @param string $name Name of the trait + * + * @return Builder\\Trait_ The created trait builder + */', + 110 => '/** + * Creates a constant use builder. + * + * @param Node\\Name|string $name Name of the const to alias + * + * @return Builder\\Use_ The created use const builder + */', + 111 => '/** + * Creates a constant fetch node. + * + * @param string|Name $name Constant name + */', + 112 => '/** + * Gets the attributes of the node/token the error occurred at. + * + * @return array + */', + 113 => '/** @var list */', + 114 => '/** @var null|Identifier|Name|ComplexType */', + 115 => '/** + * Makes the property final. + * + * @return $this The builder instance (for fluid interface) + */', + 116 => '/** @var list */', + 117 => '/** + * Returns the built class node. + * + * @return Stmt\\Enum_ The built enum node + */', + 118 => '/** + * Makes the method private. + * + * @return $this The builder instance (for fluid interface) + */', + 119 => '/** @var list */', + 120 => '/** + * Adds an attribute group. + * + * @param Node\\Attribute|Node\\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */', + 121 => '/** + * Sets alias for used name. + * + * @param string $alias Alias to use (last component of full name by default) + * + * @return $this The builder instance (for fluid interface) + */', + 122 => '/** + * Makes the constant private. + * + * @return $this The builder instance (for fluid interface) + */', + 123 => '/** + * Creates an interface builder. + * + * @param string $name Name of the interface + */', + 124 => '/** + * Sets the return type for PHP 7. + * + * @param string|Node\\Name|Node\\Identifier|Node\\ComplexType $type + * + * @return $this The builder instance (for fluid interface) + */', + 125 => '/** @var array */', + 126 => '/** + * Sets default value for the parameter. + * + * @param mixed $value Default value to use + * + * @return $this The builder instance (for fluid interface) + */', + 127 => '/** + * Adds an attribute group. + * + * @param Node\\Attribute|Node\\AttributeGroup $attribute + * + * @return $this The builder instance (for fluid interface) + */', + 128 => '/** + * Adds multiple statements. + * + * @param (PhpParser\\Node\\Stmt|PhpParser\\Builder)[] $stmts The statements to add + * + * @return $this The builder instance (for fluid interface) + */', + 129 => '/** + * Called once after traversal. + * + * Return value semantics: + * * null: $nodes stays as-is + * * otherwise: $nodes is set to the return value + * + * @param Node[] $nodes Array of nodes + * + * @return null|Node[] Array of nodes + */', + 130 => '/** @var NameContext Naming context */', + 131 => '/** @var callable Filter callback */', + 132 => '/** + * Visitor that connects a child node to its parent node + * as well as its sibling nodes. + * + * With $weakReferences=false on the child node, the parent node can be accessed through + * $node->getAttribute(\'parent\'), the previous + * node can be accessed through $node->getAttribute(\'previous\'), + * and the next node can be accessed through $node->getAttribute(\'next\'). + * + * With $weakReferences=true attribute names are prefixed by "weak_", e.g. "weak_parent". + */', + 133 => '/** + * @deprecated Use NodeVisitor::DONT_TRAVERSE_CHILDREN instead. + */', + 134 => '/** + * Recursively traverse a node. + * + * @param Node $node Node to traverse. + */', + 135 => '/** @var string|null Token placed at end of doc string to ensure it is followed by a newline. + * Null if flexible doc strings are used. */', + 136 => '/** + * @var array Map From "{$class}->{$subNode}" to string that should be inserted + * between elements of this list subnode. + */', + 137 => '/** + * Pretty prints a file of statements (includes the opening '/** + * Prints reformatted text of the passed comments. + * + * @param Comment[] $comments List of comments + * + * @return string Reformatted text of comments + */', + 139 => '/** + * Determines whether the LHS of a call must be wrapped in parenthesis. + * + * @param Node $node LHS of a call + * + * @return bool Whether parentheses are required + */', + 140 => '/** @var \\ReflectionClass[] Node type to reflection class map */', + 141 => '/** @var Version */', + 142 => '/** @var Requirement[] */', + 143 => '/** + * @throws InvalidUrlException + */', + 144 => '/** @var null|Email */', + 145 => '/** @var int */', + 146 => '/** @var LibXMLError[] */', + 147 => '/** + * @throws NoPreReleaseSuffixException + */', + 148 => '/** + * @throws InvalidPreReleaseSuffixException + */', + 149 => '/** @var int */', + 150 => '/** @var resource */', + 151 => '/** @var string */', + 152 => '/** + * @param string $phpExecutable + * @param string $output + * @param bool $isHhvmType + * @return PhpExecutable + * @throws RunTimeException + */', + 153 => '/** + * @param PhpExecutable $phpExecutable + * @param string $fileToCheck Path to file to check + * @param bool $aspTags + * @param bool $shortTag + * @param bool $deprecated + * @throws RunTimeException + */', + 154 => '/** + * @return string + * @throws RunTimeException + */', + 155 => '/** @var int */', + 156 => '/** + * @param int $parallelJobs + * @return ParallelLint + */', + 157 => '/** + * @param $showDeprecated + * @return ParallelLint + */', + 158 => '/** @var array */', + 159 => '/** @var array */', + 160 => '/** + * @return int + */', + 161 => '/** @var bool */', + 162 => '/** + * @return string + */', + 163 => '/** + * (PHP 5 >= 5.4.0)
+ * Specify data which should be serialized to JSON + * @link http://php.net/manual/en/jsonserializable.jsonserialize.php + * @return mixed data which can be serialized by json_encode, + * which is a value of any type other than a resource. + */', + 164 => '/** @var IWriter */', + 165 => '/** + * @param int $count + */', + 166 => '/** + * @param string $string + */', + 167 => '/** + * Check PHP code inside ASP-style <% %> tags. + * @var bool + */', + 168 => '/** + * Path to git executable for blame + * @var string + */', + 169 => '/** + * @return array + */', + 170 => '/** + * @return array + */', + 171 => '/** + * @template T of NodeAbstract + * @param array $args + * @return list|null + */', + 172 => '/** + * @return array + */', + 173 => '/** + * The file type mapper. + * + */', + 174 => '/** + * @implements Rule + */', + 175 => '/** + * @param Arg[] $args + */', + 176 => '/** + * @implements Rule + */', + 177 => '/** + * @implements Rule + */', + 178 => '/** + * @phpstan-implements Rule + */', + 179 => '/** + * @phpstan-extends OperandInArithmeticIncrementOrDecrementRule + */', + 180 => '/** + * @implements Rule + */', + 181 => '/** + * @var Wizard + */', + 182 => '/** + * @var ?FileAnalyser + */', + 183 => '/** + * Sets the test data. + */', + 184 => '/** + * @throws UnintentionallyCoveredCodeException + */', + 185 => '/** + * @var array + */', + 186 => '/** + * @psalm-param Identifier|Name|ComplexType $type + */', + 187 => '/** + * @return mixed + */', + 188 => '/** + * @var array + */', + 189 => '/** + * @throws PhpdbgNotAvailableException + */', + 190 => '/** + * @throws NoCodeCoverageDriverWithPathCoverageSupportAvailableException + * @throws Xdebug2NotEnabledException + * @throws Xdebug3NotEnabledException + * @throws XdebugNotAvailableException + * + * @deprecated Use DriverSelector::forLineAndPathCoverage() instead + */', + 191 => '/** + * @throws PcovNotAvailableException + */', + 192 => '/** + * @param int[] $lines + */', + 193 => '/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + */', + 194 => '/** @var int $line */', + 195 => '/** + * @var string + */', + 196 => '/** + * @var Project + */', + 197 => '/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + */', + 198 => '/** + * @var DOMElement + */', + 199 => '/** + * @var DOMElement + */', + 200 => '/** + * @var string + */', + 201 => '/** + * @internal This class is not covered by the backward compatibility promise for phpunit/php-code-coverage + */', + 202 => '/** + * Moves forward to next element. + */', + 203 => '/** + * @var File[] + */', + 204 => '/** + * @var int + */', + 205 => '/** + * @psalm-return array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int} + */', + 206 => '/** + * @var array + */', + 207 => '/** + * @var array + */', + 208 => '/** + * @psalm-param array{linesOfCode: int, commentLinesOfCode: int, nonCommentLinesOfCode: int} $linesOfCode + */', + 209 => '/** + * @var float + */', + 210 => '/** + * @throws Throwable + */', + 211 => '/** + * @var int + */', + 212 => '/** + * @return list + */', + 213 => '/** @psalm-param class-string $className */', + 214 => '/** + * Returns the name of the failing test (including data set, if any). + */', + 215 => '/** + * @var ?bool + */', + 216 => '/** + * @var TestFailure[] + */', + 217 => '/** + * @var bool + */', + 218 => '/** + * @var bool + */', + 219 => '/** + * @var bool + */', + 220 => '/** + * Informs the result that a test will be started. + */', + 221 => '/** + * Returns an array of TestFailure objects for the skipped tests. + * + * @return TestFailure[] + */', + 222 => '/** + * Runs a TestCase. + * + * @throws \\SebastianBergmann\\CodeCoverage\\InvalidArgumentException + * @throws CodeCoverageException + * @throws InvalidArgumentException + * @throws UnintentionallyCoveredCodeException + */', + 223 => '/** + * Returns the error-to-exception conversion setting. + */', + 224 => '/** + * Enables or disables the stopping for skipped tests. + */', + 225 => '/** + * @internal + */', + 226 => '/** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @param mixed $other value or object to evaluate + */', + 227 => '/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */', + 228 => '/** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @param mixed $other value or object to evaluate + */', + 229 => '/** + * @var string + */', + 230 => '/** + * Returns a string representation of the constraint. + */', + 231 => '/** + * @var string + */', + 232 => '/** + * @var array + */', + 233 => '/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */', + 234 => '/** + * Returns a string representation of the constraint. + */', + 235 => '/** + * Translates a given type to a human readable message prefix. + */', + 236 => '/** + * @var Constraint + */', + 237 => '/** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @param mixed $other evaluated value or object + * + * @throws InvalidArgumentException + */', + 238 => '/** + * Returns the number of operands (constraints). + */', + 239 => '/** + * Returns the number of operands. + */', + 240 => '/** + * @var Constraint + */', + 241 => '/** + * Returns the name of this operator. + */', + 242 => '/** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @param mixed $other value or object to evaluate + */', + 243 => '/** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @param mixed $other value or object to evaluate + */', + 244 => '/** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @param mixed $other evaluated value or object + */', + 245 => '/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */', + 246 => '/** + * Returns a string representation of the constraint. + * + * @throws InvalidArgumentException + */', + 247 => '/** + * Returns a string representation of the constraint. + */', + 248 => '/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */', + 249 => '/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */', + 250 => '/** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * This method can be overridden to implement the evaluation algorithm. + * + * @param mixed $other value or object to evaluate + * + * @codeCoverageIgnore + */', + 251 => '/** + * Counts the number of constraint elements. + */', + 252 => '/** + * Asserts that a haystack does not contain a needle. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * @throws Exception + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotContains + */', + 253 => '/** + * Asserts that two variables are not equal. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEquals + */', + 254 => '/** + * Asserts that a value is smaller than or equal to another value. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertLessThanOrEqual + */', + 255 => '/** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotEqualsFile + */', + 256 => '/** + * Asserts that a directory does not exist. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryDoesNotExist + */', + 257 => '/** + * Asserts that a file does not exist. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @codeCoverageIgnore + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4077 + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileNotExists + */', + 258 => '/** + * Asserts that a condition is not false. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @psalm-assert !false $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotFalse + */', + 259 => '/** + * Asserts that an object has a specified attribute. + * + * @param object $object + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * @throws Exception + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectHasAttribute + */', + 260 => '/** + * Asserts that a variable is of type float. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @psalm-assert float $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsFloat + */', + 261 => '/** + * Asserts that a variable is not of type array. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @psalm-assert !array $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotArray + */', + 262 => '/** + * Asserts that a variable is not of type callable. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @psalm-assert !callable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotCallable + */', + 263 => '/** + * Asserts that a string matches a given format file. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringMatchesFormatFile + */', + 264 => '/** + * Asserts that two XML files are equal. + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * @throws Exception + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlFileEqualsXmlFile + */', + 265 => '/** + * Asserts that two given JSON encoded objects or arrays are not equal. + * + * @param string $expectedJson + * @param string $actualJson + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringNotEqualsJsonString + */', + 266 => '/** + * Returns a matcher that matches when the method is executed + * exactly $count times. + */', + 267 => '/** + * @var int + */', + 268 => '/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */', + 269 => '/** + * @var int + */', + 270 => '/** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */', + 271 => '/** + * @throws \\PHPUnit\\Framework\\Exception + */', + 272 => '/** + * @var bool + */', + 273 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 274 => '/** + * @var string + */', + 275 => '/** + * @var Stub + */', + 276 => '/** + * @var bool + */', + 277 => '/** + * @throws RuntimeException + */', + 278 => '/** + * @var mixed + */', + 279 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 280 => '/** + * Looks up the match builder with identification $id and returns it. + * + * @param string $id The identification of the match builder + */', + 281 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 282 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 283 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 284 => '/** + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */', + 285 => '/** + * @param mixed[] $arguments + * + * @throws \\PHPUnit\\Framework\\Exception + * @throws MethodNameNotConfiguredException + * @throws MethodParametersAlreadyConfiguredException + * + * @return $this + */', + 286 => '/** + * @param int $argumentIndex + * + * @return self + */', + 287 => '/** + * @var string + */', + 288 => '/** + * @var Generator + */', + 289 => '/** + * Specifies the name for the mock class. + * + * @return $this + */', + 290 => '/** + * Disables the invocation of the original methods. + * + * @return $this + */', + 291 => '/** + * @var Template[] + */', + 292 => '/** + * @throws ReflectionException + * + * @return MockMethod[] + */', + 293 => '/** + * @var bool + */', + 294 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 295 => '/** + * Wrapper for getMessage() which is declared as final. + */', + 296 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 297 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 298 => '/** + * @var string[] + * + * @deprecated Use $backupGlobalsExcludeList instead + */', + 299 => '/** + * @var int|string + */', + 300 => '/** + * @var MockObject[] + */', + 301 => '/** + * @var mixed + */', + 302 => '/** + * @var bool + */', + 303 => '/** + * Returns a matcher that matches when the method is executed + * at the given index. + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4297 + * + * @codeCoverageIgnore + */', + 304 => '/** + * @psalm-param class-string $exception + */', + 305 => '/** + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/5062 + */', + 306 => '/** + * @throws InvalidArgumentException + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */', + 307 => '/** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */', + 308 => '/** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */', + 309 => '/** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */', + 310 => '/** + * Returns the normalized test name as class::method. + * + * @return list + */', + 311 => '/** + * Mocks the specified class and returns the name of the mocked class. + * + * @param null|array $methods $methods + * + * @psalm-template RealInstanceType of object + * + * @psalm-param class-string|string $originalClassName + * + * @psalm-return class-string + * + * @deprecated + */', + 312 => '/** + * Get the mock object generator, creating it if it doesn\'t exist. + */', + 313 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 314 => '/** + * @var null|ExceptionWrapper + */', + 315 => '/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */', + 316 => '/** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws Exception + * @throws ExpectationFailedException + */', + 317 => '/** + * Asserts that a variable is empty. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + * + * @psalm-assert empty $actual + */', + 318 => '/** + * Asserts that the contents of one file is not equal to the contents of another + * file (canonicalizing). + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + */', + 319 => '/** + * Asserts that a file/dir exists and is not readable. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + * + * @codeCoverageIgnore + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4062 + */', + 320 => '/** + * Asserts that a directory exists and is writable. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + */', + 321 => '/** + * Asserts that a file exists and is not writable. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + */', + 322 => '/** + * Asserts that a variable is nan. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + */', + 323 => '/** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + */', + 324 => '/** + * Asserts that a variable is of type resource and is closed. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + * + * @psalm-assert resource $actual + */', + 325 => '/** + * Asserts that a variable is not of type object. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + * + * @psalm-assert !object $actual + */', + 326 => '/** + * Asserts that a string does not match a given regular expression. + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + * + * @codeCoverageIgnore + * + * @deprecated https://github.com/sebastianbergmann/phpunit/issues/4089 + */', + 327 => '/** + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + */', + 328 => '/** + * Asserts that two XML documents are not equal. + * + * @param DOMDocument|string $expectedXml + * @param DOMDocument|string $actualXml + * + * @throws \\SebastianBergmann\\RecursionContext\\InvalidArgumentException + * @throws ExpectationFailedException + * @throws Xml\\Exception + */', + 329 => '/** + * @throws Exception + */', + 330 => '/** + * Reset the assertion counter. + */', + 331 => '/** + * @var int + */', + 332 => '/** + * The number of tests in the test suite. + * + * @var int + */', + 333 => '/** + * Returns a string representation of the test suite. + */', + 334 => '/** @psalm-var class-string $className */', + 335 => '/** + * @return list + */', + 336 => '/** + * @var int + */', + 337 => '/** + * An error occurred. + */', + 338 => '/** + * Formats a buffer with a specified ANSI color sequence if colors are + * enabled. + */', + 339 => '/** + * @var ?string + */', + 340 => '/** + * @var ?string + */', + 341 => '/** + * @var ?bool + */', + 342 => '/** + * @var ?bool + */', + 343 => '/** + * @var ?bool + */', + 344 => '/** + * @var null|string[] + */', + 345 => '/** + * @var ?bool + */', + 346 => '/** + * @var ?bool + */', + 347 => '/** + * @var ?string + */', + 348 => '/** + * @var ?string + */', + 349 => '/** + * @throws Exception + */', + 350 => '/** + * @throws Exception + */', + 351 => '/** + * @throws Exception + */', + 352 => '/** + * @throws Exception + */', + 353 => '/** + * @throws Exception + */', + 354 => '/** + * @throws Exception + */', + 355 => '/** + * @throws Exception + */', + 356 => '/** + * @throws Exception + */', + 357 => '/** + * @throws Exception + */', + 358 => '/** + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */', + 359 => '/** + * @var Timer + */', + 360 => '/** + * @var mixed + */', + 361 => '/** + * @var VariableCollection + */', + 362 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */', + 363 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 364 => '/** + * @var File[] + */', + 365 => '/** + * @var string + */', + 366 => '/** + * @var ExtensionCollection + */', + 367 => '/** + * @throws Exception + * @throws MigrationBuilderException + * @throws MigrationException + * @throws XmlException + */', + 368 => '/** + * @throws MigrationException + */', + 369 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 370 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */', + 371 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @psalm-immutable + */', + 372 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */', + 373 => '/** + * @var TestFileCollection + */', + 374 => '/** + * @deprecated + */', + 375 => '/** + * @param Directory[] $directories + */', + 376 => '/** + * @var FileCollection + */', + 377 => '/** + * @var ?Crap4j + */', + 378 => '/** + * @throws Exception + */', + 379 => '/** + * @throws Exception + */', + 380 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @psalm-immutable + */', + 381 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 382 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @psalm-immutable + */', + 383 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */', + 384 => '/** + * @var bool + */', + 385 => '/** + * @var bool + */', + 386 => '/** + * @var bool + */', + 387 => '/** + * @var bool + */', + 388 => '/** + * @var bool + */', + 389 => '/** + * @throws Exception + */', + 390 => '/** + * @throws Exception + */', + 391 => '/** + * @return Extension[] + */', + 392 => '/** + * @param Group[] $groups + */', + 393 => '/** + * @psalm-var list + */', + 394 => '/** + * Show the help message. + */', + 395 => '/** + * Prettify json string. + * + * @throws Exception + */', + 396 => '/** + * Defines if should use STDERR redirection or not. + * + * Then $stderrRedirection is TRUE, STDERR is redirected to STDOUT. + */', + 397 => '/** + * Runs a single test in a separate PHP process. + * + * @throws InvalidArgumentException + */', + 398 => '/** + * Handles creating the child process and returning the STDOUT and STDERR. + * + * @throws Exception + */', + 399 => '/** + * @return \'!=\'|\'<\'|\'<=\'|\'<>\'|\'=\'|\'==\'|\'>\'|\'>=\'|\'eq\'|\'ge\'|\'gt\'|\'le\'|\'lt\'|\'ne\' + */', + 400 => '/** + * @throws Exception + */', + 401 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 402 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @psalm-immutable + */', + 403 => '/** + * @var DOMElement[] + */', + 404 => '/** + * @param null|mixed $out + */', + 405 => '/** + * A test started. + */', + 406 => '/** + * Incomplete test. + */', + 407 => '/** + * Maps class names to source file names. + * + * - PEAR CS: Foo_Bar_Baz -> Foo/Bar/Baz.php + * - Namespace: Foo\\Bar\\Baz -> Foo/Bar/Baz.php + */', + 408 => '/** + * @todo This constant should be private (it\'s public because of TestTest::testGetProvidedDataRegEx) + */', + 409 => '/** + * @psalm-param class-string $classNameInHierarchy + */', + 410 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 411 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 412 => '/** + * Returns the missing requirements for a test. + * + * @psalm-param class-string $className + * + * @throws Exception + * @throws Warning + */', + 413 => '/** @psalm-param class-string $className */', + 414 => '/** + * @var string + */', + 415 => '/** + * @throws InvalidArgumentException + */', + 416 => '/** + * @var int[] + */', + 417 => '/** + * @var array Lookup table for testname to testResults[index] + */', + 418 => '/** + * @throws InvalidArgumentException + */', + 419 => '/** + * @var int + */', + 420 => '/** + * Flush buffer and close output. + */', + 421 => '/** + * A test ended. + */', + 422 => '/** + * @var null|Throwable + */', + 423 => '/** + * A test suite ended. + */', + 424 => '/** + * @var bool + */', + 425 => '/** + * @throws Exception + * + * @return string[] + */', + 426 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 427 => '/** + * @param array|string $args + * + * @throws Exception + */', + 428 => '/** + * @var TestResultCache + */', + 429 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 430 => '/** + * @var TestResultCache + */', + 431 => '/** + * Compares test duration for sorting tests by duration ascending. + * + * @throws InvalidArgumentException + */', + 432 => '/** + * @psalm-var array + */', + 433 => '/** + * @psalm-return array{loadedExtensions: list, notLoadedExtensions: list} + */', + 434 => '/** + * Returns the name of the test case. + */', + 435 => '/** + * @throws Exception + */', + 436 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 437 => '/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */', + 438 => '/** + * Returns the loader to be used. + */', + 439 => '/** + * Confirms if the cache contains specified cache item. + * + * Note: This method MAY avoid retrieving the cached value for performance reasons. + * This could result in a race condition with CacheItemInterface::get(). To avoid + * such situation use CacheItemInterface::isHit() instead. + * + * @param string $key + * The key for which to check existence. + * + * @throws InvalidArgumentException + * If the $key string is not a legal value a \\Psr\\Cache\\InvalidArgumentException + * MUST be thrown. + * + * @return bool + * True if item exists in the cache, false otherwise. + */', + 440 => '/** + * Retrieves the value of the item from the cache associated with this object\'s key. + * + * The value returned must be identical to the value originally stored by set(). + * + * If isHit() returns false, this method MUST return null. Note that null + * is a legitimate cached value, so the isHit() method SHOULD be used to + * differentiate between "null value was found" and "no value was found." + * + * @return mixed + * The value corresponding to this cache item\'s key, or null if not found. + */', + 441 => '/** + * @psalm-immutable + */', + 442 => '/** + * @psalm-param class-string $interfaceName + * + * @throws InvalidCodeUnitException + * @throws ReflectionException + */', + 443 => '/** + * @psalm-param class-string $className + * + * @throws ReflectionException + */', + 444 => '/** + * @psalm-assert-if-true InterfaceMethod $this + */', + 445 => '/** + * @psalm-param class-string $className + * + * @throws ReflectionException + */', + 446 => '/** + * @throws ReflectionException + */', + 447 => '/** + * Compares doubles for equality. + * + * @deprecated since v3.0.5 and v4.0.8 + */', + 448 => '/** + * @var Comparator[] + */', + 449 => '/** + * Compares Exception instances for equality. + */', + 450 => '/** + * Expected value of the retrieval which does not match $actual. + * + * @var mixed + */', + 451 => '/** + * @return string + */', + 452 => '/** + * Compares numerical values for equality. + */', + 453 => '/** + * Returns whether the comparator can compare two values. + * + * @param mixed $expected The first value to compare + * @param mixed $actual The second value to compare + * + * @return bool + */', + 454 => '/** + * @var bool + */', + 455 => '/** + * @var string + */', + 456 => '/** + * Returns true if line ends don\'t match in a diff. + */', + 457 => '/** + * Calculates the longest common subsequence of two arrays. + */', + 458 => '/** + * Defines how an output builder should take a generated + * diff array and return a string representation of that diff. + */', + 459 => '/** + * @var bool + */', + 460 => '/** + * @var int + */', + 461 => '/** + * Returns true when Zend OPcache is loaded, enabled, + * and is configured to discard comments. + */', + 462 => '/** + * A nifty utility for visualizing PHP variables. + * + * + * export(new Exception); + * + */', + 463 => '/** + * Restores a super-global variable array from this snapshot. + */', + 464 => '/** + * @var array + */', + 465 => '/** + * Creates a snapshot a super-global variable array. + */', + 466 => '/** + * @var string[] + */', + 467 => '/** + * @var int + */', + 468 => '/** + * @var SplObjectStorage + */', + 469 => '/** + * @psalm-var non-empty-string + */', + 470 => '/** + * @var bool + */', + 471 => '/** + * @throws RuntimeException + */', + 472 => '/** + * @psalm-assert-if-true MixedType $this + */', + 473 => '/** + * @var bool + */', + 474 => '/** + * @throws RuntimeException + */', + 475 => '/** + * @var string + */', + 476 => '/** + * @param int|string|array $kind + */', + 477 => '/** + * @return array + */', + 478 => '/** + * Enables fetching output and error output from the underlying process. + * + * @return $this + * + * @throws RuntimeException In case the process is already running + */', + 479 => '/** + * Returns a string representation for the exit code returned by the process. + * + * This method relies on the Unix exit code status standardization + * and might not be relevant for other operating systems. + * + * @return string|null A string representation for the exit status code, null if the Process is not terminated + * + * @see http://tldp.org/LDP/abs/html/exitcodes.html + * @see http://en.wikipedia.org/wiki/Unix_signal + */', + 480 => '/** + * Stops the process. + * + * @param int|float $timeout The timeout in seconds + * @param int|null $signal A POSIX signal to send in case the process has not stop at timeout, default is SIGKILL (9) + * + * @return int|null The exit-code of the process or null if it\'s not running + */', + 481 => '/** + * Checks if the TTY mode is enabled. + * + * @return bool + */', + 482 => '/** + * @throws LogicException in case process is not started + */', + 483 => '/** + * Reads pipes, executes callback. + * + * @param bool $blocking Whether to use blocking calls or not + * @param bool $close Whether to close file handles or not + */', + 484 => '/** + * PipesInterface manages descriptors and pipes for the use of proc_open. + * + * @author Romain Neutron + * + * @internal + */', + 485 => '/** + * {@inheritdoc} + */', + 486 => '/** + * @author Romain Neutron + * + * @internal + */', + 487 => '/** + * Finds an executable by name. + * + * @param string $name The executable name (without the extension) + * @param string|null $default The default to return if no executable is found + * @param array $extraDirs Additional dirs to check into + * + * @return string|null + */', + 488 => '/** + * Validates and normalizes a Process input. + * + * @param string $caller The name of method call that validates the input + * @param mixed $input The input to validate + * + * @return mixed + * + * @throws InvalidArgumentException In case the input is not valid + */', + 489 => '/** + * Tells whether the write buffer is closed or not. + */', + 490 => '/** @var int */', +); diff --git a/tally.php b/tally.php new file mode 100644 index 00000000..8ccd998f --- /dev/null +++ b/tally.php @@ -0,0 +1,10 @@ +withPaths([__DIR__ . '/benchmarks']); diff --git a/tools/tally/composer.json b/tools/tally/composer.json new file mode 100644 index 00000000..e7b71d50 --- /dev/null +++ b/tools/tally/composer.json @@ -0,0 +1,11 @@ +{ + "description": "Dev-only Tally, which counts the benchmarks in benchmarks/ and asks for a PHP this library still runs without.", + "require": { + "phpstan/tally": "dev-release/1.x" + }, + "minimum-stability": "dev", + "prefer-stable": true, + "config": { + "sort-packages": true + } +} diff --git a/tools/tally/composer.lock b/tools/tally/composer.lock new file mode 100644 index 00000000..8e751728 --- /dev/null +++ b/tools/tally/composer.lock @@ -0,0 +1,75 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "e7746d1dd0595500782c29bf94c17c00", + "packages": [ + { + "name": "phpstan/tally", + "version": "dev-release/1.x", + "source": { + "type": "git", + "url": "https://github.com/phpstan/tally.git", + "reference": "b4807df7eac302f3e61258bf7187b5be0defe3d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/tally/zipball/b4807df7eac302f3e61258bf7187b5be0defe3d9", + "reference": "b4807df7eac302f3e61258bf7187b5be0defe3d9", + "shasum": "" + }, + "require": { + "ext-posix": "*", + "php": "^8.2" + }, + "require-dev": { + "infection/infection": "^0.35.10", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^11.5 || ^12.5", + "shipmonk/dead-code-detector": "^1.4" + }, + "bin": [ + "bin/tally" + ], + "type": "library", + "autoload": { + "psr-4": { + "Tally\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHP benchmarking framework that doesn't care about wall-clock time or how fast your CPU is.", + "keywords": [ + "benchmark", + "codspeed", + "performance" + ], + "support": { + "issues": "https://github.com/phpstan/tally/issues", + "source": "https://github.com/phpstan/tally/tree/release/1.x" + }, + "time": "2026-11-14T12:13:34+00:00", + "published-time": "2026-11-14T12:13:40+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "dev", + "stability-flags": { + "phpstan/tally": 20 + }, + "prefer-stable": true, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.11.0" +}