|
| 1 | +--- |
| 2 | +description: Pre-output checklist, naming, typing, comparisons, and PHPDoc rules for all PHP files in libraries. |
| 3 | +paths: |
| 4 | + - "src/**/*.php" |
| 5 | + - "tests/**/*.php" |
| 6 | +--- |
| 7 | + |
| 8 | +# Code style |
| 9 | + |
| 10 | +Semantic code rules for all PHP files. Formatting rules (PSR-1, PSR-4, PSR-12, line length) are enforced by `phpcs.xml` |
| 11 | +and are not repeated here. Refer to `rules/domain.md` for domain modeling rules. |
| 12 | + |
| 13 | +## Pre-output checklist |
| 14 | + |
| 15 | +Verify every item before producing any PHP code. If any item fails, revise before outputting. |
| 16 | + |
| 17 | +1. `declare(strict_types=1)` is present. |
| 18 | +2. All classes are `final readonly` by default. Use `class` (without `final` or `readonly`) only when the class is |
| 19 | + designed as an extension point for consumers (e.g., `Collection`, `ValueObject`). Use `final class` without |
| 20 | + `readonly` only when the parent class is not readonly (e.g., extending a third-party abstract class). |
| 21 | +3. All parameters, return types, and properties have explicit types. |
| 22 | +4. Constructor property promotion is used. |
| 23 | +5. Named arguments are used at call sites for own code, tests, and third-party library methods (e.g., tiny-blocks). |
| 24 | + Never use named arguments on native PHP functions (`array_map`, `in_array`, `preg_match`, `is_null`, |
| 25 | + `iterator_to_array`, `sprintf`, `implode`, etc.). |
| 26 | +6. No `else` or `else if` exists anywhere. Use early returns, polymorphism, or map dispatch instead. |
| 27 | +7. No abbreviations appear in identifiers. Use `$index` instead of `$i`, `$account` instead of `$acc`. |
| 28 | +8. No generic identifiers exist. Use domain-specific names instead: |
| 29 | + `$data` → `$payload`, `$value` → `$totalAmount`, `$item` → `$element`, |
| 30 | + `$info` → `$details`, `$result` → `$outcome`. |
| 31 | +9. No raw arrays exist where a typed collection or value object is available. Use `tiny-blocks/collection` |
| 32 | + (`Collection`, `Collectible`) instead of raw `array` for any list of domain objects. Raw arrays are acceptable |
| 33 | + only for primitive configuration data, variadic pass-through, or interop at system boundaries. |
| 34 | +10. No private methods exist except private constructors for factory patterns. Inline trivial logic at the call site |
| 35 | + or extract it to a collaborator or value object. |
| 36 | +11. Members are ordered: constants first, then constructor, then static methods, then instance methods. Within each |
| 37 | + group, order by body size ascending (number of lines between `{` and `}`). Constants and enum cases, which have |
| 38 | + no body, are ordered by name length ascending. |
| 39 | +12. Constructor parameters are ordered by parameter name length ascending (count the name only, without `$` or type), |
| 40 | + except when parameters have an implicit semantic order (e.g., `$start/$end`, `$from/$to`, `$startAt/$endAt`), |
| 41 | + which takes precedence. The same rule applies to named arguments at call sites. |
| 42 | + Example: `$id` (2) → `$value` (5) → `$status` (6) → `$precision` (9). |
| 43 | +13. No O(N²) or worse complexity exists. |
| 44 | +14. No logic is duplicated across two or more places (DRY). |
| 45 | +15. No abstraction exists without real duplication or isolation need (KISS). |
| 46 | +16. All identifiers, comments, and documentation are written in American English. |
| 47 | +17. No justification comments exist (`// NOTE:`, `// REASON:`, etc.). Code speaks for itself. |
| 48 | +18. `// TODO: <reason>` is used when implementation is unknown, uncertain, or intentionally deferred. |
| 49 | + Never leave silent gaps. |
| 50 | +19. All class references use `use` imports at the top of the file. Fully qualified names inline are prohibited. |
| 51 | +20. No dead or unused code exists. Remove unreferenced classes, methods, constants, and imports. |
| 52 | +21. Never create public methods, constants, or classes in `src/` solely to serve tests. If production code does not |
| 53 | + need it, it does not exist. |
| 54 | + |
| 55 | +## Naming |
| 56 | + |
| 57 | +- Names describe **what** in domain terms, not **how** technically: `$monthlyRevenue` instead of `$calculatedValue`. |
| 58 | +- Generic technical verbs (`process`, `handle`, `execute`, `mark`, `enforce`, `manage`, `ensure`, `validate`, |
| 59 | + `check`, `verify`, `assert`, `transform`, `parse`, `compute`, `sanitize`, `normalize`) **should be avoided**. |
| 60 | + Prefer names that describe the domain operation. |
| 61 | +- Booleans use predicate form: `isActive`, `hasPermission`, `wasProcessed`. |
| 62 | +- Collections are always plural: `$orders`, `$lines`. |
| 63 | +- Methods returning bool use prefixes: `is`, `has`, `can`, `was`, `should`. |
| 64 | + |
| 65 | +## Comparisons |
| 66 | + |
| 67 | +1. Null checks: use `is_null($variable)`, never `$variable === null`. |
| 68 | +2. Empty string checks on typed `string` parameters: use `$variable === ''`. Avoid `empty()` on typed strings because |
| 69 | + `empty('0')` returns `true`. |
| 70 | +3. Mixed or untyped checks (value may be `null`, empty string, `0`, or `false`): use `empty($variable)`. |
| 71 | + |
| 72 | +## American English |
| 73 | + |
| 74 | +All identifiers, enum values, comments, and error codes use American English spelling: |
| 75 | +`canceled` (not `cancelled`), `organization` (not `organisation`), `initialize` (not `initialise`), |
| 76 | +`behavior` (not `behaviour`), `modeling` (not `modelling`), `labeled` (not `labelled`), |
| 77 | +`fulfill` (not `fulfil`), `color` (not `colour`). |
| 78 | + |
| 79 | +## PHPDoc |
| 80 | + |
| 81 | +- PHPDoc is restricted to interfaces only, documenting obligations and `@throws`. |
| 82 | +- Never add PHPDoc to concrete classes. |
0 commit comments