Yandex Metrika
sanches.free

Извлечь все комментарии из PHP-файла: token_get_all и потоковый ввод

Зачем это вообще

В легаси‑коде, агенте или кастомном модуле «1С‑Битрикс» комментарии часто живут дольше, чем живой контекст: там остаются временные объяснения, отключённые куски и PHPDoc, который IDE уже не показывает. Если нужен быстрый снимок «по тексту без исполнения кода», удобнее не регулярками вырезать /* … */, а пройти токены так, как делает парсер PHP.

Лексический разбор: token_get_all

Функция token_get_all($source) возвращает массив токенов. Каждый элемент либо массив [id, текст, строка], либо одиночная строковая пунктуация вида ; или {. Комментарии приходят как T_COMMENT (одно- и многострочные в актуальных версиях) и как T_DOC_COMMENT для PHPDoc-блоков. В PHP 8+ набора типов уже меньше, чем во времена PHP 4 (T_ML_COMMENT больше не используется) — этого достаточно для задачи выборки текстов комментариев.

Скрипт: читаем файл из stdin

Так можно подставлять «кот» из нескольких файлов или использовать тот же бинарь в пайплайне CI. Обратите внимание: буфер исходного текста нужно явно обнулить, и массив с типами комментариев лучше проверять в строгом режиме in_array(..., true), чтобы не поймать неожиданное приведение типов.

declare(strict_types=1);

final class StreamCommentHarvest
{
    private string $aggregate = '';

    /* идентификаторы T_COMMENT и T_DOC_COMMENT */
    private const INTERESTING = [
        T_COMMENT,
        T_DOC_COMMENT,
    ];

    public function consumeStdin(): void
    {
        $stdin = fopen('php://stdin', 'rb');
        if ($stdin === false) {
            throw new RuntimeException('Cannot open stdin');
        }
        try {
            while (!feof($stdin)) {
                $chunk = fread($stdin, 8192);
                if ($chunk === false) {
                    break;
                }
                if ($chunk !== '') {
                    $this->aggregate .= $chunk;
                }
            }
        } finally {
            fclose($stdin);
        }
    }

    /**
     * Список фрагментов исходника, помеченных как комментарии.
     */
    public function collectCommentBodies(): array
    {
        if ($this->aggregate === '') {
            return [];
        }
        $pieces = token_get_all($this->aggregate);
        $out = [];
        foreach ($pieces as $item) {
            if (!is_array($item)) {
                continue;
            }
            [$id, $text] = [$item[0], $item[1]];
            if (!in_array($id, self::INTERESTING, true)) {
                continue;
            }
            $out[] = $text;
        }

        return $out;
    }

    public function printBodies(): void
    {
        foreach ($this->collectCommentBodies() as $block) {
            echo $block, PHP_EOL;
        }
    }
}

$harvest = new StreamCommentHarvest();
$harvest->consumeStdin();
$harvest->printBodies();

Запуск

Один файл:

php extract-comments.php < local/modules/itd.vendor/lib/LegacyFacade.php

Небольшой дерево обход через find — помните о кавычках и ограничениях командной строки; для глубоких проектов логичнее сначала сформировать список файлов и читать их по одному через PHP или xargs с ограничением параллелизма, чтобы не упираться в квоты.

Чего инструмент не делает

  • Комментарии внутри строковых литералов и интерполяций здесь считаются обычным текстом строки — именно этого хочет язык при токенизации.
  • «Мёртвый» код за #if в условной компиляции у PHP отсутствует; здесь просто текст исходника.
  • Для доверенного аудита секретов нужны отдельные проверки: комментарий не выполняется, но текст может содержать URL и пароли — вывод сохраняйте в файл с нужными правами.

Кратко

token_get_all даёт синтаксически честную выборку T_COMMENT/T_DOC_COMMENT; связка со stdin упрощает автоматизацию вокруг Битрикс‑дерева и легаси‑скриптов без подключения ядра.

Не хотите копаться сами?

Починю за 1-3 дня. Без предоплаты — оплата по результату.

15+ лет опыта с 1С-Битрикс · Без предоплаты · 7 дней гарантии