Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHPStanのエラーをprettyにしようとしている

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Natsuki Natsuki
November 22, 2025
12

 PHPStanのエラーをprettyにしようとしている

Avatar for Natsuki

Natsuki

November 22, 2025
Tweet

Transcript

  1. PHPStan使ってますか public ?int $age return $this->age + 1; <?php class

    User { public function __construct( public string $name, ) {} public function nextAge(): int { } }
  2. VSCodeのエラーは見づら過ぎる!! /** * @return array{ * id: int, * name:

    string, * // ... * } */ function getProfile(): array { return [ 'id' => 123, 'name' => 'John Doe', // ... ]; }
  3. パーサーを使わないアプローチ パーサーは作らずエラーパターンからマッチさせる /Function 関数名 should return 型(array{...}) but returns 型(array{...})./

    エラーの種類だけ、パターンマッチで拾う エラーパターンの変更を追従するのが大変 & プラグインの数だけ対応が必要 => 汎用的にエラー文をパースできた方がいい
  4. ちなみにpretty-ts-errorsは正規表現 https://github.com/yoavbls/pretty-ts- errors/blob/8527285178e9a88c80ad63fa7f0129192b67bad2/packages/formatter/ TSはエラーパターンが決まってるからできる `${pre}${formatTypeBlock("", type, codeBlock)}: <ul>${post .split(", ")

    .filter(Boolean) .map((prop: string) => `<li>${prop}</li>`) .join("")}</ul>` message .replaceAll( /(is missing the following properties from type\s?)'(.*)': ((?:#?\w+, )*(?:(?!and)\w+)?)/g, (_, pre, type, post) => )
  5. 例 this.RULE("object", () => { this.CONSUME(LCurly); this.MANY_SEP({ SEP: Comma, DEF:

    () => { this.SUBRULE(this.objectItem); }, }); this.CONSUME(RCurly); }); class JsonParser extends CstParser { constructor() { this.RULE("json", () => { this.OR([ { ALT: () => this.SUBRULE(this.object) }, { ALT: () => this.SUBRULE(this.array) }, ]); }); this.RULE("objectItem", () => { this.CONSUME(StringLiteral); this.CONSUME(Colon); this.SUBRULE(this.value);
  6. パーサーの定義の前に字句解析(Lexer) const True = createToken({ name: "True", pattern: /true/ });

    const False = createToken({ name: "False", pattern: /false/ }); const Null = createToken({ name: "Null", pattern: /null/ }); const LCurly = createToken({ name: "LCurly", pattern: /{/ }); const RCurly = createToken({ name: "RCurly", pattern: /}/ });
  7. 使い方 import { parse } from 'phpstan-error-parser'; const result =

    parse('PHPDoc tag @mixin contains unresolvable type.') [ { type: 'common_word', value: 'PHPDoc', location: { startColumn: 0, endColumn: 6, }, }, { type: 'common_word', value: 'tag', location: { startColumn: 7, endColumn: 10, }, }, { type: 'doc_tag', value: '@mixin',