What do Pest's php, security and strict arch presets each enforce, and how do you exempt one function from a preset?
answer
- predefined bundles of arch expectations
- php: debug output and removed functions
- security: md5, eval, unserialize, rand
- strict: strict_types, ===, final classes
- ->ignoring('md5') on the preset
basics
~10 sarch()->preset()->php() bans debug and output calls such as var_dump and die, security() bans risky calls such as eval, md5 and unserialize, and strict() demands declare(strict_types=1), strict equality and final classes; ->ignoring('md5') exempts one entry.
solid answer
~40 sPresets are ready-made bundles of arch expectations. In Pest 5.2 `arch()->preset()->php()` forbids debugging and output helpers (`var_dump`, `print_r`, `dump`, `die`, `echo`, `phpinfo`, the `xdebug_*` functions) plus long-removed ones such as the `mysql_*` family and `ereg`. `security()` forbids `md5`, `sha1`, `rand`, `mt_rand`, `uniqid`, `eval`, `exec`, `shell_exec`, `system`, `unserialize`, `extract`, `assert` and a few more. `strict()` runs, for each PSR-4 namespace in your composer.json, `toUseStrictTypes()`, `toUseStrictEquality()`, final and non-abstract classes, no protected methods, and bans `sleep`/`usleep`. To keep a legitimate use, chain `->ignoring('md5')` or a namespace onto the preset. The strict checks are textual: `toUseStrictEquality()` fails on the characters ` == ` anywhere in the file, even in a comment.
code
php · 7 lines<?php
arch()->preset()->php()->ignoring('App\Console');
arch()->preset()->security()->ignoring('md5');
arch()->preset()->strict();go deeper
Remember the three preset names and one example of what each bans: var_dump for php, md5 or eval for security, missing strict types for strict.
Explain that presets expand into ordinary arch expectations over your PSR-4 namespaces, and how ignoring() narrows one of them.
Know the textual nature of toUseStrictTypes() and toUseStrictEquality(), the opinionated parts of strict, and how to phase presets into a legacy codebase without a flood of failures.
Weigh whether the strict preset's opinions (no abstract classes, no protected methods) match the codebase's design, and decide which rules become organisation-wide presets.
## What a preset is In Pest, an **arch preset** is a named, predefined set of architecture expectations that you switch on with one line inside the suite: ```php arch()->preset()->php(); arch()->preset()->security()->ignoring('md5'); arch()->preset()->strict(); ``` Each preset is a class under `Pest\ArchPresets` whose `execute()` method builds a list of ordinary arch expectations. The namespaces a preset applies to come from your project's **PSR-4 autoload map** in `composer.json`, so `App\` in a typical application is picked up without configuration. Pest 5 ships `php`, `security`, `strict`, `relaxed` and `laravel`, and lets you register your own with `pest()->presets()->custom('name', fn (array $userNamespaces) => [...])`. ## What each preset forbids or requires (Pest 5.2) | Preset | Kind of rule | Examples from the source | |---|---|---| | `php` | functions that must not be used | `var_dump`, `print_r`, `var_export`, `dump`, `die`, `echo`, `print`, `phpinfo`, `goto`, `global`, `debug_backtrace`, `xdebug_*`, `mysql_*`, `ereg` | | `security` | functions that must not be used | `md5`, `sha1`, `rand`, `mt_rand`, `uniqid`, `str_shuffle`, `shuffle`, `array_rand`, `tempnam`, `eval`, `exec`, `shell_exec`, `system`, `passthru`, `unserialize`, `extract`, `mb_parse_str`, `assert`, `dl`, `create_function` (removed in PHP 8.0) | | `strict` | per-namespace structure rules | `toUseStrictTypes()`, `toUseStrictEquality()`, classes final, classes not abstract, no protected methods, and no `sleep`/`usleep` | | `relaxed` | the opposite of `strict` | no strict types, no final classes | - The `php` preset is about **leftovers**: debugging output, direct echoing from classes, and functions removed from PHP years ago that still sit in old code. - The `security` preset is about **risky primitives**: weak hashes, predictable random sources, code and shell execution, and deserialisation of untrusted data. It flags the call; judging whether a given call is actually exploitable is still a human job. - The `strict` preset is about **style that the team has chosen**. It is opinionated: it forbids abstract classes and protected methods outright, which suits a composition-first codebase and fights an inheritance-heavy one. ## How toUseStrictTypes() and toUseStrictEquality() actually check Both are text checks on the file, which is worth knowing before a failure surprises you: 1. `toUseStrictTypes()` runs a regular expression over the file text that requires `declare(strict_types=1);` right after the opening `<?php`, with only whitespace and comments allowed in between. It never loads or parses the file as PHP, so it reports the file and line, not a semantic finding. 2. `toUseStrictEquality()` fails if the file contains the substring ` == ` or ` != ` anywhere, including inside a comment or a string literal. It is a string search, not a parse of comparison operators. So a docblock that says `// returns true if $a == $b` will fail the `strict` preset. ## Exempting what is legitimate Every preset returns an object with an `ignoring()` method that forwards to each of its arch expectations: - `arch()->preset()->security()->ignoring('md5');` keeps `md5` legal everywhere, for example when it is used as a cache-key hash rather than for passwords. - `arch()->preset()->php()->ignoring('App\Console');` excludes a namespace, which fits CLI commands that legitimately `echo`. - Narrow is better: ignoring one namespace keeps the rule armed for the rest of the codebase, while ignoring a function lifts it everywhere. ## Writing your own preset When a set of rules repeats across services, a **custom preset** packages it. `pest()->presets()->custom('ddd', function (array $userNamespaces) { return [...]; })` registers a preset whose closure receives the project's PSR-4 namespaces and returns a list of expectations, for example `expect('Infrastructure')->toOnlyBeUsedIn('Application')`. After registration, `arch()->preset()->ddd()` runs it like a built-in one, and `ignoring()` works on it the same way. This is the route a plugin author or a platform team takes to ship house rules to many repositories; inside a single project, plain `arch()` calls are easier to read and review. ## Using presets in CI - Start with `php` and `security` on an existing codebase: they are cheap, rarely controversial, and catch the stray `dd()`-style call before it ships. - Treat `strict` as a decision the team makes, not a default. On legacy code it produces hundreds of failures at once; adopt it per namespace with your own `arch()` rules first, or ignore legacy namespaces until they are converted. - Presets run as ordinary tests, so they fail the same `./vendor/bin/pest` command CI already runs. Their exact contents can change between Pest releases, so read the preset classes when you upgrade.
- Why might the strict preset fail on a file whose code uses === everywhere?Because `toUseStrictEquality()` is a substring check for ` == ` and ` != ` over the whole file. A comment or a string literal containing those characters fails it even when no loose comparison exists in the code. Rewording the comment fixes it.
- Where does a preset get the list of namespaces it applies to?From the project's PSR-4 namespaces as Composer declares them in composer.json. The preset reads them once and runs its per-namespace rules for each, so a new PSR-4 root is picked up as soon as it is declared, with no list to maintain in Pest.php.
- When would you write a custom preset instead of arch() rules?When the same set of rules is reused across several projects or shipped by a plugin. `pest()->presets()->custom('ddd', fn (array $namespaces) => [...])` registers it, and `arch()->preset()->ddd()` runs it. Inside one project, plain `arch()` calls are usually clearer.
saying these in an interview costs you the question
- The security preset proves the code has no vulnerabilities
- toUseStrictTypes() accepts declare(strict_types=1) anywhere in the file
- toUseStrictEquality() parses operators, so comments cannot fail it
- The strict preset only checks declare(strict_types=1)
- Presets need their namespaces configured by hand in Pest.php
- Exempting a function means deleting the preset line