據 AlphaMoat 統計,截至 2026-09,PHP 累計下載 4,238 次、獲 6 個星標,在全部 5,078 個 AI 技能中排名第 2,353 位,在「開發程式設計」分類(577 個)中排名第 303 位。
| 平台 | 累計安裝 | 累計下載 | 星標 | 評論 |
|---|---|---|---|---|
| ClawHub ↗ | 86 | 3279 | 4 | - |
| SkillHub ↗ | 180 | 4238 | 6 | — |
各平台的計數口徑不同,統計時間不一致。
文件覆蓋 PHP 型別處理、陣列、物件導向、Composer、PDO、會話、PHP-FPM 與 OPcache 等主題,也描述常見錯誤的排查。Laravel 內部機制不在其範圍內;修復方案應根據使用者提供的程式碼和執行環境驗證。
資料釋出於 2026-10-27
以下是根據技能文件生成的示例,不代表實際執行結果。
2026-09 起統計方法調整:同名技能按作者分別統計,並覆蓋全部技能。圖中虛線為調整前的月份,與之後的資料不直接比較,也不計算跨越調整的增長。
| 月份 | 累計下載 | 環比 | 星標 |
|---|---|---|---|
| 2026-09 | 4238 | — | 6 |
| 2026-08 | 3067 | +15.4% | 6 |
| 2026-07 | 2658 | +18.6% | 5 |
| 2026-06 | 2241 | +6.7% | 5 |
| 2026-05 | 2101 | — | 5 |
| 2026-03 | 1585 | — | 4 |
以下是作者釋出的原始檔案,按純文字顯示,本站未做修改或稽核;其中的連結不可點選,命令請核實後再執行。抓取於 2026-10-23。
--- name: php slug: php version: 1.0.2 changelog: "Full coverage pass: deeper guides, situation-named files, and per-user configuration" description: >- Writes, debugs, and reviews PHP: type juggling, arrays, OOP, Composer, PDO, sessions, PHP-FPM, OPcache, PHP 8 features. Use when PHP returns a blank white page or a 500 with no message, when "headers already sent", "Allowed memory size exhausted", "Maximum execution time exceeded", "Class not found" after a Composer install, or an undefined array key warning appears; when `==` compares wrong, `strpos` or `preg_match` returns a falsy match, accents turn into mojibake,
`DateTime` shifts by a day or an hour, `json_encode` returns false, PDO refuses to bind a parameter or emulates
prepares, sessions serialize parallel AJAX requests, nginx answers 502 or 504 in front of PHP-FPM, OPcache keeps
serving old code, or a version upgrade breaks on deprecations. Also for escaping output, hashing passwords, sizing
FPM workers, writing PHPUnit tests, and clearing PHPStan errors. Not for framework internals — `laravel` covers
Eloquent, queues, and Laravel auth.
homepage: https://clawic.com/skills/php
metadata:
clawdbot:
emoji: 🐘
requires:
bins:
- php
os:
- linux
- darwin
- win32
displayName: PHP
configPaths:
- ~/Clawic/data/php/
---
User preferences live in `~/Clawic/data/php/config.yaml` (see Configuration); nothing else is stored on the user's machine. If you have data at an old location (`~/php/` or `~/clawic/php/`), move it to `~/Clawic/data/php/`.
## When To Use
- Writing or reviewing PHP — read Core Rules and Output Gates before emitting code
- Any error whose cause is not obvious in ten seconds: white page, silent 500, wrong value with no exception, a hang
- Runtime and deployment work: php.ini precedence, FPM pool sizing, OPcache, CLI workers, cron
- Dependency and upgrade work: Composer constraints, autoloading, deprecations, moving to a newer 8.x
- Data-boundary work: PDO queries, JSON payloads, uploads, sessions, dates, encodings
- Hardening: escaping per context, password hashing, deserialization, path containment, upload validation
- Not for framework internals — `laravel` owns Eloquent, queues, Blade, and Laravel auth
## Quick Reference
| Situation | Play |
|-----------|------|
| `==` compares wrong, a numeric string misbehaves, floats do not add up | `===` everywhere; `"0e12" == "0e34"` is true → `hash_equals` → `types.md` |
| Keys vanish, order is wrong, a filtered list encodes as a JSON object | `array_filter` keeps keys; `array_values()` before encoding → `arrays.md` |
| Accents break, `strlen` disagrees with what you see, a regex silently fails | `mb_*` for text, `/u` on every pattern, check `preg_last_error()` → `strings.md` |
| Class design: traits, `static::`, readonly, enums, magic methods, clone | `self::` binds at compile time, `static::` at call time → `oop.md` |
| Exceptions, error handlers, warnings you cannot see, fatal errors | Catch `\Throwable`; fatals need `register_shutdown_function` → `errors.md` |
| Injection, XSS, uploads, `unserialize`, passwords, tokens | Bind every value, escape per output context, `random_bytes` for secrets → `security.md` |
| Which PHP 8 feature to use, and how it bites | `match` is strict and exhaustive; named args make parameter names API → `modern.md` |
| Upgrading PHP, a deprecation wall, "which version can I still target" | Run the OLD version with deprecations as errors first → `versions.md` |
| `Class not found`, lock conflicts, `^` vs `~`, slow or huge installs | Commit the lock for apps, never for libraries → `composer.md` |
| White page, silent 500, "it worked yesterday", a hang with no output | Symptom → cause chains, plus the Xdebug 3 setup that actually works → `debugging.md` |
| Slow requests, high memory, "should we turn on JIT" | OPcache first, profile second; JIT does almost nothing for I/O-bound web → `performance.md` |
| A setting you changed has no effect; CLI and web disagree | `php --ini` per SAPI; `.user.ini` is cached for 300s → `php-ini.md` |
| 502, 504, "server reached pm.max_children", workers eating RAM | Size from measured RSS; `slowlog` names the hung function → `fpm.md` |
| Console scripts, daemons, cron, signals, exit codes | `max_execution_time` is 0 on CLI; recycle workers on a job count → `cli.md` |
| PHPUnit setup, flaky or falsely-passing tests, coverage, mocks | `assertSame` not `assertEquals`; static state leaks between tests → `testing.md` |
| PHPStan or Psalm errors, baselines, coding standard, automated refactors | Baseline the legacy, ratchet one level per merge → `static-analysis.md` |
| PDO connections, binding, transactions, "MySQL server has gone away" | `charset=utf8mb4` in the DSN, `EMULATE_PREPARES => false` → `database.md` |
| Request/response handling, JSON bodies, uploads, outbound HTTP calls | JSON bodies live in `php://input`, not `$_POST` → `http.md` |
| Parallel requests from one user run one at a time; logins do not stick | `session_start()` holds an exclusive lock — `session_write_close()` early → `sessions.md` |
| Dates off by a day or an hour, DST, parsing, storage | `DateTimeImmutable` + IANA zones; `createFromFormat` inherits today → `datetime.md` |
| `json_decode` returns null, big IDs lose digits, `json_encode` returns false | Always pass `JSON_THROW_ON_ERROR` → `json.md` |
| Reading or writing files, CSV, streams, temp files, permissions | Stream instead of slurping; write temp then `rename()` → `files.md` |
| Parallel work, queues, locks across processes, long-running runtimes | Share-nothing per request; `proc_open` deadlocks if you read one pipe → `concurrency.md` |
| Anything else | Core Rules below, then reproduce with `php -d error_reporting=E_ALL -d display_errors=1 -r '<five suspect lines>'` and add one thing back at a time |
Each file above is one sub-job and is self-contained: read SKILL.md by default, open exactly one guide when the situation matches.
## Core Rules
1. `declare(strict_types=1);` on line 1 of every file. It is per-file and governs the CALLS made in that file, not the functions declared there — so an untyped legacy caller still passes `"7"` into your `int` parameter. Return values are checked against the mode of the file where the function is DECLARED (`types.md`).
2. `===` and `!==` by default; `==` only where both operand types are proven. Worked case: `"0e12" == "0e34"` is `true` because both are numeric strings equal to 0 — a hash compared with `==` accepts the wrong password. Compare digests with `hash_equals($known, $given)`, which is also constant-time.
3. Check anything that can return `false` with `!== false`, never with truthiness. `strpos($haystack, $needle)` returns `0` for a match at offset 0, and `if (!strpos(...))` reads that correct answer as a miss; the same shape breaks `preg_match` (`0` = no match, `false` = engine error) and `file_get_contents` (`""` is a valid file).
4. Every SQL value is a bound parameter; every identifier comes from an allowlist you wrote. Placeholders cannot stand in for table or column names, and with the MySQL driver's default emulation the "prepared" statement is interpolated client-side — set `PDO::ATTR_EMULATE_PREPARES => false` (`database.md`).
5. Escape at output, per context, never at input. `htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')` covers HTML body and quoted attributes only; a value going into JavaScript needs `json_encode` with the HEX flags, one going into a URL needs `rawurlencode`, one going into a shell needs `escapeshellarg` (`security.md`).
6. Text is characters, not bytes: `strlen`, `substr`, `str_pad`, `strrev`, and `ucfirst` count bytes and will cut a UTF-8 sequence in half. Use `mb_strlen`/`mb_substr`/`mb_str_pad` (`php >=8.3`) for anything a human reads; keep the byte functions for binary data, where they are the correct tool.
7. `DateTimeImmutable` everywhere. `DateTime::modify()` mutates the object that every reference shares, so a helper that "returns tomorrow" also moves the caller's date. The same call on an immutable returns a new instance and the bug cannot happen (`datetime.md`).
8. Every call that leaves the process gets an explicit timeout: `CURLOPT_TIMEOUT` plus `CURLOPT_CONNECTTIMEOUT`, a stream context `timeout` for `fopen`, `PDO::ATTR_TIMEOUT` for connections. `max_execution_time` will not save you — on Unix it does not count time spent inside system calls, so a hung socket read is only killed by FPM's `request_terminate_timeout` (`fpm.md`).
9. Stream instead of slurping. `file_get_contents` on a 400 MB export needs 400 MB plus copies inside the default 128M `memory_limit`; `fgetcsv` in a loop, or a generator, holds one row. The same rule retires `fetchAll()` on large result sets (`files.md`, `performance.md`).
## Version Floors
The floors that shape everyday code. Individual guides carry more, inline in this same `php >=X.Y` form next to the instruction each one gates. Support windows and the upgrade procedure: `versions.md`.
| Feature | Needs |
|---|---|
| Typed properties, arrow functions `fn() =>`, spread in calls, `??=`, covariant return types | php >=7.4 |
| `match`, named arguments, constructor promotion, `?->`, union types, attributes, `str_contains`/`str_starts_with`/`str_ends_with`, `static` return type, `throw` as an expression, saner string-to-number comparison, PDO defaulting to exception error mode | php >=8.0 |
| Enums, `readonly` properties, fibers, `never`, first-class callables `f(...)`, `new` in initializers, `array_is_list()`, string-keyed array unpacking, overridable interface constants, `htmlspecialchars` escaping single quotes by default | php >=8.1 |
| `readonly` classes, DNF types, `null`/`false`/`true` as standalone types, locale-independent `strtolower`/`strtoupper`, dynamic properties deprecated, `${var}` interpolation deprecated | php >=8.2 |
| Typed class constants, `#[\Override]`, `json_validate()`, `mb_str_pad()`, readonly reinitialization inside `__clone`, stack-overflow detection via `zend.max_allowed_stack_size` | php >=8.3 |
| Property hooks, asymmetric visibility, `new Foo()->m()` without parentheses, lazy objects, `array_find`/`array_any`/`array_all`, `mb_trim`, implicit nullable parameters (`Foo $x = null`) deprecated | php >=8.4 |
| Pipe operator `\|>`, `#[\NoDiscard]` | php >=8.5 |
## Output Gates
Before delivering PHP code, check:
- `declare(strict_types=1);` present, and every parameter, property, and return typed as narrowly as the value allows
- No `==`, `!=`, or `switch` on values whose types are not both proven; `in_array` and `array_search` carry `true` as the strict flag
- Every SQL value bound, every identifier allowlisted, `EMULATE_PREPARES` off
- Every value reaching HTML, an attribute, JavaScript, a URL, or a shell escaped with that context's function, at the point of output
- Nothing user-controlled reaches `unserialize`, `include`/`require`, `eval`, `extract`, a filesystem path, or a `header()` value without validation
- Every outbound call (HTTP, DB, subprocess, lock) has a timeout, and every `false`-returning call has its return inspected
- Dates are `DateTimeImmutable` with an explicit IANA timezone; human-facing text handled with `mb_*`
- `json_encode`/`json_decode` carry `JSON_THROW_ON_ERROR`
- Syntax and functions stay within `min_php`; layout matches `style`; new behavior arrives with a test that was seen failing first
## Configuration
User-dependent variables. Defaults apply until the user states a preference; store them in `~/Clawic/data/php/config.yaml`. Never interview the user — record a preference the moment it is stated.
| Variable | Type | Default | Effect |
|---|---|---|---|
| min_php | 7.4 \| 8.0 \| 8.1 \| 8.2 \| 8.3 \| 8.4 \| 8.5 | 8.2 | Gates which Version Floors features may be emitted unguarded, and which fallback appears instead (`versions.md`) |
| sapi | fpm \| cli \| apache-mod \| swoole \| roadrunner | fpm | Assumptions about request lifetime, static state, timeouts, and where output goes (`fpm.md`, `cli.md`, `concurrency.md`) |
| framework | none \| laravel \| symfony \| wordpress \| slim | none | Whether to emit plain PHP or framework idiom, and when to hand off to a framework skill |
| strict_types | always \| new-files \| never | always | Whether emitted files open with `declare(strict_types=1)`, and how coercion is discussed (`types.md`) |
| style | per-cs \| psr-12 \| custom | per-cs | Layout of emitted code and the fixer ruleset produced (`static-analysis.md`) |
| static_analysis | none \| phpstan \| psalm | phpstan | Which checker's annotations, config file, and baseline commands appear (`static-analysis.md`) |
| analysis_level | number (0-9) | 6 | Strictness assumed when annotating, and whether a docblock is required alongside a native type (`static-analysis.md`) |
| test_framework | phpunit \| pest \| none | phpunit | Shape of emitted tests, assertions, and data providers (`testing.md`) |
| db_layer | pdo \| doctrine \| eloquent \| mysqli | pdo | Which data-access idiom every query example uses (`database.md`) |
Preference areas — customizable dimensions; a stated preference gets recorded in config.yaml and applied:
- **Tooling**: fixer (PHP-CS-Fixer vs PHP_CodeSniffer), Rector adoption, Xdebug vs pcov for coverage, profiler of choice, local runtime (Docker, Homebrew, Valet, WSL) — affects every emitted config block and command
- **Conventions**: namespace and directory layout, DTO style (arrays vs readonly classes vs enums), exception hierarchy, naming, docblock policy — affects generated code and review comments
- **Platform**: deployment target (FPM behind nginx, shared hosting, container, serverless, long-running runtime), OS, extension availability (`ext-intl`, `ext-mbstring`, `ext-pcntl`), private Packagist — affects `composer.md`, `php-ini.md`, `fpm.md`
- **Safety posture**: how aggressively to flag `unserialize`, dynamic `include`, `extract`, `@`, missing timeouts, unpinned dependencies, and emulated prepares — affects `security.md` and review depth
- **Dependencies**: banned or mandated packages (Guzzle vs Symfony HttpClient, Carbon vs native `DateTimeImmutable`), tolerance for new transitive dependencies, stdlib-only constraints — affects every recommendation
- **Output format**: whole file vs minimal diff, how much explanation, whether tests and a changelog entry accompany every change — affects the shape of the answer, never the correctness rules
- **Work order**: which gates run before a change is proposed rather than after — analyzer and suite green first, a plan approved before editing, a profile before any optimization — affects the sequence of every task, never the correctness rules
## Traps
| Trap | Why it fails | Do instead |
|------|-------------|------------|
| `if (!strpos($s, $x))` | Returns `0` for a match at position 0 — the correct answer reads as failure | `strpos($s, $x) !== false`, or `str_contains()` on `php >=8.0` (`strings.md`) |
| `==` to compare a password hash or token | `"0e12" == "0e34"` is `true`; both are numeric strings equal to zero | `hash_equals()`, or `password_verify()` for passwords (`security.md`) |
| `array_filter()` then `json_encode()` | Keys survive, so the gap turns the array into a JSON object and the client's `.map()` fails | `array_values()` after every filter that feeds JSON (`arrays.md`, `json.md`) |
| `json_decode($s)` with no flags | Returns `null` for the input `"null"` AND for a parse error — indistinguishable | Always `JSON_THROW_ON_ERROR` (`json.md`) |
| `$_POST` for a JSON request body | Populated only for form-encoded and multipart bodies | `json_decode(file_get_contents('php://input'), ...)` (`http.md`) |
| Trusting `$_FILES['f']['type']` | The MIME type is supplied by the client and is trivially forged | `finfo_file()` on the temp file plus an extension allowlist (`security.md`) |
| `session_start()` at the top and never closing | The session lock is held for the whole request, so one user's parallel requests execute one at a time | `session_write_close()` as soon as the last write is done (`sessions.md`) |
| `DateTime::createFromFormat('Y-m-d', $d)` | Unspecified fields default to NOW, so the date carries the current time and can roll the day | Prefix the format with `!` to zero them, then check `getLastErrors()` (`datetime.md`) |
| `@` to silence a warning | Hides the diagnosis and leaves the broken value in flight; on `php >=8.0` it no longer even silences fatals | Handle the failure, or narrow `error_reporting` deliberately (`errors.md`) |
| `mt_rand`/`uniqid()` for a token or password reset | Predictable: `uniqid()` is a formatted timestamp, `mt_rand` is a seeded PRNG | `random_bytes()`/`random_int()` (`security.md`) |
| `PDO::ATTR_PERSISTENT` without cleanup | A worker inherits an open transaction, session variables, or temporary tables from the previous request | Non-persistent connections, or an explicit rollback on checkout (`database.md`) |
| A closing `?>` at the end of a PHP file | One trailing newline becomes output, and every later `header()` fails with "headers already sent" | Omit the closing tag in pure-PHP files (`http.md`) |
| `readfile()` for a large download | Fills the output buffer with the whole file before sending | `fpassthru` with buffers flushed, or `X-Accel-Redirect`/`X-Sendfile` (`http.md`) |
| `opcache.validate_timestamps=0` with a deploy that only swaps files | Workers keep executing the previous release's bytecode | Reload FPM (`kill -USR2`) as the last deploy step (`performance.md`, `fpm.md`) |
| `SELECT` then `INSERT` to avoid duplicates | Two workers pass the check in the same millisecond | Unique index plus catching the duplicate-key error (`concurrency.md`) |
## Where Experts Disagree
- **Arrays vs objects for structured data.** The array-shape school keeps everything a `list<array{id:int,…}>` and lets the analyzer verify it: no boilerplate, refactors are grep-based. The value-object school makes each shape a readonly class: constructor validation, no key typos, IDE completion. Boundary: data crossing a module or process boundary earns a class; a shape used in three lines of one function does not (`static-analysis.md`).
- **Active record vs data mapper.** Eloquent-style records are faster to write and let any layer reach the database; Doctrine-style mappers keep the domain persistence-free and make the unit of work explicit. Boundary: how long the codebase must outlive its storage decisions — not how large it is (`database.md`).
- **How strict to run the analyzer.** One camp treats anything below `max` as unfinished; the other stops where the false-positive rate exceeds the bug-catch rate. Boundary: a greenfield typed domain reaches high levels cheaply; a decade-old codebase baselines and ratchets, and measures success as baseline shrinkage rather than level number (`static-analysis.md`).
- **Long-running runtimes.** Swoole, RoadRunner, and FrankenPHP remove per-request bootstrap and can cut latency materially; they also delete PHP's strongest safety property, that every request starts from a clean process. Boundary: adopt when bootstrap is a measured share of p95 AND the team accepts hunting state leaks — never as a default (`concurrency.md`).
- **Framework or none.** A framework supplies routing, DI, migrations, and a hiring pool; plain PHP with a few PSR packages supplies a dependency tree you can read end to end. Boundary: the number of cross-cutting concerns you would otherwise hand-write — auth, queues, and migrations together is the tipping point.
## Related Skills
More Clawic skills, get them at https://clawic.com/skills/php (install if the user confirms):
- `laravel` — Eloquent, queues, Blade, and Laravel-specific auth
- `mysql` — schema design, indexes, and query plans behind PDO
- `nginx` — the server in front of PHP-FPM: buffering, timeouts, static files
- `regex` — PCRE pattern design; this skill's `strings.md` covers only the PHP bindings
- `debugging` — language-agnostic fault isolation; the PHP-specific version is this skill's `debugging.md`
## Feedback
- If useful, star it: https://clawic.com/skills/php
- Latest version: https://clawic.com/skills/php
Part of [Clawic](https://clawic.com), the verified skill library. Get this skill: https://clawic.com/skills/php.
用 gh 命令列工具檢視 GitHub 上的 PR 檢查、工作流執行與 API 查詢的技能。
聚合 16 個搜尋引擎、無需 API Key 的檢索技能。
用命令列直接列出、配置、授權並呼叫 MCP 服務與工具。
生成有效的 Mermaid 圖表,如流程圖、時序圖、思維導圖、ER 圖、使用者旅程等。
用受管 OAuth 訪問 YouTube Data API,檢索影片並管理頻道內容。
透過受管的 OAuth 連線訪問 GitHub REST API。
覆蓋規劃、實現、驗證與測試的編碼工作流技能。
整理 Docker 常用命令與容器工作流的技能。
將使用者明確糾正與自我檢視整理成分層記憶,並依使用情況升級或封存。
在保留公式、格式和活頁簿結構的前提下建立、檢查或編輯 Excel 檔案。
處理 Word 與 DOCX 文件的作業指南,著重維持樣式、編號與版面。
把資料庫、表格與匯出的原始資料變成可決策結論的資料分析技能。
協助編輯 PowerPoint 簡報,並在交付前檢查版面是否正常呈現。
資料月份:2026-09 · 下載/星標/安裝數聚合自公開技能註冊庫(ClawHub、SkillHub),按月更新。口徑說明見資料方法。