@@ -44,27 +44,45 @@ Verify every item before producing any PHP code. If any item fails, revise befor
44445 . Classes follow the rules in "Inheritance and constructors". ` final readonly ` is the default,
4545 with documented exceptions for extension points and for parents that are not ` readonly ` .
46466 . Members are ordered constants first, then constructor, then static methods, then instance
47- methods. Within each group, order by body size ascending (number of lines between ` { ` and ` } ` ).
48- Constants and enum cases, which have no body, are ordered by name length ascending. This
49- ordering may be overridden only when the alternative carries explicit documentation value:
50- grouping by domain class with section markers (HTTP status codes by 1xx/2xx/3xx/etc),
51- mirroring the order of an implemented interface, or similar evident structure. The override
52- must be obvious at first reading.
47+ methods. Within each group, order by ** member name length ascending** (count the name only,
48+ without parentheses, arguments, or return type). Constants, enum cases, and methods share
49+ the same name-length-ascending rule, applied within their respective groups. This mirrors
50+ the rule that governs constructor parameters and named arguments (rule 7). When two names
51+ have equal length, order them alphabetically. This ordering may be overridden only when the
52+ alternative carries explicit documentation value: grouping by domain class with section
53+ markers (HTTP status codes by 1xx/2xx/3xx/etc), mirroring the order of an implemented
54+ interface, or similar evident structure. The override must be obvious at first reading.
5355
5456 ** At call sites** (chained method calls in production code, tests, or documentation
55- examples), consecutive method invocations on the same receiver are ordered by the ** visible
56- width ** of each call expression ascending. The body is not visible at the call site, so the
57- visible width is the practical proxy for body size. Boolean toggles such as ` ->secure() ` and
58- ` ->httpOnly() ` come before parameterized ` with* ` builders for the same reason . When two
59- calls have equal width , order them alphabetically by method name .
57+ examples), consecutive method invocations on the same receiver are ordered by ** method name
58+ length ascending ** , the same rule that governs member declarations. Boolean toggles such as
59+ ` ->secure() ` and ` ->httpOnly() ` come before parameterized ` with* ` builders because their
60+ names are shorter, not because the expression is narrower . When two method names have equal
61+ length , order them alphabetically.
6062
6163 ** Terminal methods that change the receiver type** stay at the end of the chain regardless
62- of width . A ` build() ` that returns the built value, a ` commit() ` that finalizes a unit of
63- work, a ` send() ` that flushes a request, are terminal: the chain ends with them. The
64+ of name length . A ` build() ` that returns the built value, a ` commit() ` that finalizes a unit
65+ of work, a ` send() ` that flushes a request, are terminal: the chain ends with them. The
6466 ordering rule applies only to consecutive calls on the same receiver type; calls that
6567 transition to a different type are not reorderable. The same applies in reverse to the
6668 factory or accessor that starts the chain (` Cookie::create(...) ` , ` $repository ` ) — it stays
6769 at its position.
70+
71+ ** PHPUnit test classes** follow a dedicated sub-grouping inside the instance-methods group
72+ that overrides the name-length-ascending rule:
73+
74+ 1 . ** Lifecycle hooks** first, in PHPUnit execution order:
75+ ` setUpBeforeClass ` → ` setUp ` → ` tearDown ` → ` tearDownAfterClass ` . Only those actually
76+ defined appear; never introduce an empty hook to satisfy the rule.
77+ 2 . ** Test methods** (prefix ` test ` ) next, ordered by name length ascending (alphabetical
78+ tiebreak).
79+ 3 . ** Data providers** last, ordered by name length ascending (alphabetical tiebreak).
80+
81+ A method is a data provider if and only if its name appears as the string argument of a
82+ ` #[DataProvider('<name>')] ` attribute or a ` @dataProvider <name> ` docblock annotation on a
83+ test method in the same class. The naming convention (` *DataProvider ` ) is informational
84+ only; the reference is the authoritative signal. A method named ` *DataProvider ` that no
85+ test references is dead code under rule 17, not a data provider.
68867 . Constructor parameters are ordered by parameter name length ascending (count the name only,
6987 without ` $ ` or type), except when parameters have an implicit semantic order (for example,
7088 ` $start/$end ` , ` $from/$to ` , ` $startAt/$endAt ` ), which takes precedence. Parameters with default
@@ -225,10 +243,7 @@ are `canceled` (not `cancelled`), `organization` (not `organisation`), `initiali
225243
226244### When required
227245
228- - Every method of an interface, ** including interfaces declared inside ` src/Internal/ ` ** .
229- Interfaces define contracts. The contract is documentation by definition, regardless of
230- namespace. The ` Internal/ ` boundary applies to implementations, not to the contracts that
231- internal collaborators expose to each other.
246+ - Every method of an interface.
232247- Every public method of a concrete class outside ` src/Internal/ ` . Public classes are at the
233248 public API boundary by definition. Consumers call every public method directly, and the
234249 PHPDoc is the contract for each call. Trivial getters and ` with* ` methods are not exempt.
@@ -244,10 +259,7 @@ are `canceled` (not `cancelled`), `organization` (not `organisation`), `initiali
244259 interface. The interface carries the docblock.
245260- Anything inside ` src/Internal/ ` . Internal types are implementation detail and must not carry
246261 PHPDoc. The namespace itself is the boundary. See ` php-library-architecture.md ` for the
247- architectural meaning of ` Internal/ ` . ** Exception** : interfaces and their methods. An
248- interface declared inside ` src/Internal/ ` still defines a contract, and the contract is
249- documented per ` ### When required ` regardless of namespace. The prohibition covers concrete
250- classes, traits, enums, and anonymous classes inside ` Internal/ ` , never interfaces.
262+ architectural meaning of ` Internal/ ` .
251263- Anywhere inside ` tests/ ` . Test methods name the scenario via the ` testXxxWhenYyyGivenThenZzz `
252264 naming convention, and the ` @Given ` /` @When ` /` @Then ` /` @And ` annotation blocks defined in
253265 ` php-library-testing.md ` describe the steps. PHPDoc documentation (summary plus
@@ -270,10 +282,7 @@ The PHPDoc prohibitions above take priority over the typed-array case. When PHPS
270282
271283- On a ** constructor parameter** → suppress via ` ignoreErrors ` in ` phpstan.neon.dist ` . Do not
272284 add PHPDoc.
273- - On anything inside ** ` src/Internal/ ` ** (concrete classes, traits, enums) → suppress via
274- ` ignoreErrors ` . Do not add PHPDoc. Interfaces inside ` src/Internal/ ` are the exception:
275- they carry PHPDoc per ` ### When required ` , and the PHPStan errors they raise are resolved
276- through the PHPDoc, never through ` ignoreErrors ` .
285+ - On anything inside ** ` src/Internal/ ` ** → suppress via ` ignoreErrors ` . Do not add PHPDoc.
277286- On anything inside ** ` tests/ ` ** → suppress via ` ignoreErrors ` . Do not add PHPDoc.
278287- On a ** public method of a public (non-Internal) class** → add full PHPDoc with summary,
279288 ` @param ` descriptions, and the typed-array information. The bare-tag form remains
@@ -338,8 +347,7 @@ public function __construct(public array $entries)
338347}
339348```
340349
341- ** Prohibited.** PHPDoc on a ** concrete class** inside ` src/Internal/ ` (the prohibition does
342- not extend to interfaces; see "Correct" below for an Internal/ interface):
350+ ** Prohibited.** PHPDoc on anything inside ` src/Internal/ ` :
343351
344352``` php
345353namespace TinyBlocks\Http\Internal\Client;
@@ -353,26 +361,6 @@ final readonly class Url
353361}
354362```
355363
356- ** Correct.** Interface declared ** inside ` src/Internal/ ` ** still carries PHPDoc on every
357- method. The Internal/ prohibition covers concrete classes; interfaces are exempt because they
358- are the contract:
359-
360- ``` php
361- namespace TinyBlocks\Http\Internal\Client;
362-
363- interface RequestResolver
364- {
365- /**
366- * Resolves the given URL against the configured base URL.
367- *
368- * @param string $url The path or absolute URL to resolve.
369- * @return string The absolute URL to dispatch.
370- * @throws MalformedPath If the URL violates RFC 3986.
371- */
372- public function resolve(string $url): string;
373- }
374- ```
375-
376364** Correct.** Generic array type with summary and ` @param ` description:
377365
378366``` php
0 commit comments