Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
b191b9a
feat: add PHPStan type checking configuration and composer script
huangdijia Oct 29, 2025
894922f
Add comprehensive PHPStan type tests for all helper functions (#971)
Copilot Oct 29, 2025
59894aa
Move call() tests to Functions.php and update type assertions
huangdijia Oct 29, 2025
5c47d7e
fix: remove unnecessary backslash from Throwable type hint in dispatc…
huangdijia Oct 29, 2025
1c809ee
refactor: rename check:types script to type-testing for clarity
huangdijia Oct 29, 2025
1c34be5
fix: move type-testing script to the correct position in composer.json
huangdijia Oct 29, 2025
3886513
fix: remove unnecessary blank line before type-testing script in comp…
huangdijia Oct 29, 2025
6939a70
feat: add Support.php with various utility classes and type assertions
huangdijia Oct 29, 2025
447611e
fix: add return type hints for __invoke methods in ClientBuilderFacto…
huangdijia Oct 29, 2025
4ee356d
feat: add PHPStan type assertion tests for macros component (#973)
Copilot Oct 29, 2025
f3d7040
feat: add PHPStan type testing for cache component (#972)
Copilot Oct 29, 2025
fd48474
fix: remove unused imports in Cache and Macros components
huangdijia Oct 29, 2025
6bf4907
feat: update PHPStan configuration and enhance type assertions in var…
huangdijia Oct 29, 2025
d83334e
fix: update parameter type hint for Str::of method
huangdijia Oct 29, 2025
12ba868
fix: remove unused Factory method tests in Cache Manager
huangdijia Oct 29, 2025
c4cb2c3
feat: add type testing step in CI workflow
huangdijia Oct 29, 2025
0acc572
fix: comment out unused setMultiple tests in Repository
huangdijia Oct 29, 2025
de85c6e
fix: comment out unused getMultiple tests in Repository
huangdijia Oct 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ jobs:
run: composer update -o
- name: Run Analyse
run: composer analyse src
- name: Run Type Tests
run: composer type-testing
- name: Setup Services
run: ./.travis/setup.services.sh
- name: Run Test Cases
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@
],
"test:lint": "@php vendor/bin/php-cs-fixer fix --dry-run --diff --ansi",
"test:types": "@php vendor/bin/pest --type-coverage",
"test:unit": "@php vendor/bin/pest"
"test:unit": "@php vendor/bin/pest",
"type-testing": "phpstan analyze --configuration=\"phpstan.types.neon.dist\" --memory-limit=-1"
}
}
12 changes: 12 additions & 0 deletions phpstan.types.neon.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
parameters:
level: max
paths:
- types
scanFiles:
- src/macros/output/Hyperf/Collection/Arr.php
- src/macros/output/Hyperf/Collection/Collection.php
- src/macros/output/Hyperf/Collection/LazyCollection.php
- src/macros/output/Hyperf/HttpServer/Contract/RequestInterface.php
- src/macros/output/Hyperf/HttpServer/Request.php
- src/macros/output/Hyperf/Stringable/Str.php
- src/macros/output/Hyperf/Stringable/Stringable.php
9 changes: 9 additions & 0 deletions src/macros/output/Hyperf/Collection/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@

class Collection
{
/**
* Create a new collection.
*
* @param mixed $items
*/
public function __construct($items = [])
{
}

/**
* Determine if the collection contains a single element.
* @deprecated since v3.1, use `containsOneItem` instead, will be removed in v3.2.
Expand Down
18 changes: 18 additions & 0 deletions src/macros/output/Hyperf/Collection/LazyCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,24 @@

class LazyCollection
{
/**
* Create a new lazy collection instance.
*
* @param mixed $items
* @return static
*/
public static function make($items = [])
{
}

/**
* Determine if the collection contains a single element.
* @return bool
*/
public function isSingle()
{
}

/**
* Collapse the collection of items into a single array while preserving its keys.
*
Expand Down
302 changes: 302 additions & 0 deletions src/macros/output/Hyperf/HttpServer/Request.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
<?php

declare(strict_types=1);
/**
* This file is part of friendsofhyperf/components.
*
* @link https://github.com/friendsofhyperf/components
* @document https://github.com/friendsofhyperf/components/blob/main/README.md
* @contact huangdijia@gmail.com
*/

namespace Hyperf\HttpServer;

use Closure;
use Hyperf\Support\Fluent;
use Psr\Http\Message\ServerRequestInterface;

class Request
{
/**
* Get an array of all of the files on the request.
*/
public function allFiles(): array
{
}

/**
* Determine if the request contains a non-empty value for any of the given inputs.
*
* @param array|string $keys
*/
public function anyFilled($keys): bool
{
}

/**
* Retrieve input as a boolean value.
*
* Returns true when value is "1", "true", "on", and "yes". Otherwise, returns false.
*
* @param null|string $key
* @param bool $default
*/
public function boolean($key = null, $default = false): bool
{
}

/**
* Retrieve input from the request as a collection.
*/
public function collect(null|array|string $key = null): \Hyperf\Collection\Collection
{
}

/**
* Retrieve input from the request as a Carbon instance.
*/
public function date(string $key, ?string $format = null, ?string $tz = null): ?\Carbon\Carbon
{
}

/**
* Get all of the input except for a specified array of items.
*
* @param array|mixed $keys
*/
public function except($keys): array
{
}

/**
* @param null|Closure(ServerRequestInterface):ServerRequestInterface $closure
*/
public static function fake(?Closure $closure = null): ServerRequestInterface
{
}

/**
* Determine if the request contains a non-empty value for an input item.
*/
public function filled(array|string $key): bool
{
}

public function float(string $key, $default = null): float
{
}

/**
* Retrieve input from the request as a Fluent object instance.
*/
public function fluent(null|array|string $key = null): Fluent
{
}

/**
* Determine if the request contains any of the given inputs.
*/
public function hasAny(array|string $keys): bool
{
}

/**
* Determine if the given input key is an empty string for "has".
*/
public function isEmptyString(string $key): bool
{
}

/**
* Determine if the request contains an empty value for an input item.
*/
public function isNotFilled(array|string $key): bool
{
}

/**
* Get the keys for all of the input and files.
*/
public function keys(): array
{
}

/**
* Get the host name.
*/
public function host(): string
{
}

public function getHost(): string
{
}

/**
* Get the HTTP host being requested.
*/
public function httpHost(): string
{
}

public function getHttpHost(): string
{
}

public function getPort(): int
{
}

public function getPsrRequest(): ?ServerRequestInterface
{
}

public function getScheme(): string
{
}

public function isSecure(): bool
{
}

public function getSchemeAndHttpHost(): string
{
}

/**
* Get the scheme and HTTP host.
*/
public function schemeAndHttpHost(): string
{
}

/**
* Merge new input into the current request's input array.
*
* @return $this
*/
public function merge(array $input): self
{
}

/**
* Merge new input into the request's input, but only when that key is missing from the request.
*
* @return $this
*/
public function mergeIfMissing(array $input): self
{
}

/**
* Determine if the request is missing a given input item key.
*
* @param array|string $key
*/
public function missing($key): bool
{
}

/**
* Get a subset containing the provided keys with values from the input data.
*
* @param array|mixed $keys
*/
public function only($keys): array
{
}

/**
* Determine if the current request is asking for JSON.
*/
public function wantsJson(): bool
{
}

/**
* Apply the callback if the request contains a non-empty value for the given input item key.
*
* @return $this|mixed
*/
public function whenFilled(string $key, callable $callback, ?callable $default = null)
{
}

/**
* Apply the callback if the request contains the given input item key.
*
* @return $this|mixed
*/
public function whenHas(string $key, callable $callback, ?callable $default = null)
{
}

/**
* Determine if the request is sending JSON.
*/
public function isJson(): bool
{
}

/**
* Retrieve input from the request as an enum.
*
* @template TEnum
*
* @param string $key
* @param class-string<TEnum> $enumClass
* @return null|TEnum
*/
public function enum($key, $enumClass)
{
}

/**
* Determine if the request contains a given input item key.
*
* @param array|string $key
*/
public function exists($key): bool
{
}

/**
* Retrieve input from the request as a Stringable instance.
*
* @param string $key
* @param mixed $default
* @return \Hyperf\Stringable\Stringable
*/
public function str($key, $default = null)
{
}

/**
* Retrieve input from the request as a Stringable instance.
*
* @param string $key
* @param mixed $default
* @return \Hyperf\Stringable\Stringable
*/
public function string($key, $default = null)
{
}

/**
* Retrieve input as an integer value.
*
* @param string $key
* @param int $default
*/
public function integer($key, $default = 0): int
{
}

public function validate(array $rules, array $messages = [], array $customAttributes = []): array
{
}

public function validateWithBag(string $errorBag, array $rules, array $messages = [], array $customAttributes = []): array
{
}
}
Comment on lines +12 to +302
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

阻止桩类在生产环境被自动加载:建议改为 PHPStan stubs 或排除 classmap

该文件声明了完整的 Hyperf\HttpServer\Request 桩类,方法均为空且大多带返回类型。一旦被 Composer 在运行时加载:

  • 会与真实类冲突或覆盖;
  • 空方法将触发 TypeError(有返回类型却无返回)。

建议:

  • 在 composer.json 的 autoload 段增加 exclude-from-classmap: ["src/macros/output/**"];
  • 或将本文件移至 dev-only 目录并通过 phpstan.types.neon.dist 的 stubFiles/scanFiles 引入;
  • 亦可采用 if (false) {...} 的“编译期桩”模式,仅供静态分析可见。

若短期无法迁移,请至少为这些方法提供统一兜底(如直接抛出 LogicException),防止误用:

示例(选取少量代表方法,其他方法同理处理):

-    public function allFiles(): array
-    {
-    }
+    public function allFiles(): array
+    {
+        throw new \LogicException('Stub for static analysis only.');
+    }

-    public function boolean($key = null, $default = false): bool
-    {
-    }
+    public function boolean($key = null, $default = false): bool
+    {
+        throw new \LogicException('Stub for static analysis only.');
+    }

-    public static function fake(?\Closure $closure = null): \Psr\Http\Message\ServerRequestInterface
-    {
-    }
+    public static function fake(?\Closure $closure = null): \Psr\Http\Message\ServerRequestInterface
+    {
+        throw new \LogicException('Stub for static analysis only.');
+    }

此外,可在需要处添加

  • @SuppressWarnings(PHPMD.UnusedFormalParameter) 以消除未使用参数告警;
  • 或将未使用参数命名为 $_key、$_input 等。Based on learnings

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 PHPMD (2.15.0)

32-32: Avoid unused parameters such as '$keys'. (undefined)

(UnusedFormalParameter)


44-44: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


44-44: Avoid unused parameters such as '$default'. (undefined)

(UnusedFormalParameter)


51-51: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


58-58: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


58-58: Avoid unused parameters such as '$format'. (undefined)

(UnusedFormalParameter)


58-58: Avoid unused parameters such as '$tz'. (undefined)

(UnusedFormalParameter)


67-67: Avoid unused parameters such as '$keys'. (undefined)

(UnusedFormalParameter)


74-74: Avoid unused parameters such as '$closure'. (undefined)

(UnusedFormalParameter)


81-81: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


85-85: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


85-85: Avoid unused parameters such as '$default'. (undefined)

(UnusedFormalParameter)


92-92: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


99-99: Avoid unused parameters such as '$keys'. (undefined)

(UnusedFormalParameter)


106-106: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


113-113: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


178-178: Avoid unused parameters such as '$input'. (undefined)

(UnusedFormalParameter)


187-187: Avoid unused parameters such as '$input'. (undefined)

(UnusedFormalParameter)


196-196: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


205-205: Avoid unused parameters such as '$keys'. (undefined)

(UnusedFormalParameter)


221-221: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


221-221: Avoid unused parameters such as '$callback'. (undefined)

(UnusedFormalParameter)


221-221: Avoid unused parameters such as '$default'. (undefined)

(UnusedFormalParameter)


230-230: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


230-230: Avoid unused parameters such as '$callback'. (undefined)

(UnusedFormalParameter)


230-230: Avoid unused parameters such as '$default'. (undefined)

(UnusedFormalParameter)


250-250: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


250-250: Avoid unused parameters such as '$enumClass'. (undefined)

(UnusedFormalParameter)


259-259: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


270-270: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


270-270: Avoid unused parameters such as '$default'. (undefined)

(UnusedFormalParameter)


281-281: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


281-281: Avoid unused parameters such as '$default'. (undefined)

(UnusedFormalParameter)


291-291: Avoid unused parameters such as '$key'. (undefined)

(UnusedFormalParameter)


291-291: Avoid unused parameters such as '$default'. (undefined)

(UnusedFormalParameter)


295-295: Avoid unused parameters such as '$rules'. (undefined)

(UnusedFormalParameter)


295-295: Avoid unused parameters such as '$messages'. (undefined)

(UnusedFormalParameter)


295-295: Avoid unused parameters such as '$customAttributes'. (undefined)

(UnusedFormalParameter)


299-299: Avoid unused parameters such as '$errorBag'. (undefined)

(UnusedFormalParameter)


299-299: Avoid unused parameters such as '$rules'. (undefined)

(UnusedFormalParameter)


299-299: Avoid unused parameters such as '$messages'. (undefined)

(UnusedFormalParameter)


299-299: Avoid unused parameters such as '$customAttributes'. (undefined)

(UnusedFormalParameter)

🤖 Prompt for AI Agents
In src/macros/output/Hyperf/HttpServer/Request.php lines 12-302: this file is a
full runtime-declarable stub (empty methods with return types) which can be
autoloaded in production causing class conflicts or TypeErrors; fix by moving
the file out of production classmap or making it compile-time only: add
"exclude-from-classmap": ["src/macros/output/**"] to composer.json autoload, or
relocate the stub to a dev-only folder and register it only for static analysis
(phpstan.stubFiles/scanFiles), or wrap the entire class declaration in if
(false) { ... } so it’s ignored at runtime; if you cannot immediately move it,
make each method fail-safe at runtime by throwing a LogicException (or similar)
from every method to avoid returning wrong types, and annotate/rename unused
parameters (or add @SuppressWarnings annotations) to silence static analysis
warnings.

Loading