findSplitUseBlock($path, $relative)); } return $errors; } /** @return list */ private function findSplitUseBlock(string $path, string $relative): array { $lines = file($path); $errors = []; $count = count($lines); $i = $this->skipPreamble($lines); if ($i === null) { return []; } while (true) { $i = $this->consumeUseStatement($lines, $i); if ($i >= $count) { break; } $blanks = []; $j = $i; while ($j < $count) { $stripped = trim($lines[$j]); if ($stripped === '') { $blanks[] = $j; $j++; } elseif (str_starts_with($stripped, '//') || str_starts_with($stripped, '#[')) { $j++; } else { break; } } if ($j < $count && preg_match(self::USE_START_RE, trim($lines[$j]))) { foreach ($blanks as $bi) { $errors[] = "{$relative}:" . ($bi + 1) . ': blank line splits the leading `use` block'; } $i = $j; } else { break; } } return $errors; } /** @param list $lines */ private function skipPreamble(array $lines): ?int { foreach ($lines as $idx => $raw) { $stripped = trim($raw); if (preg_match(self::USE_START_RE, $stripped)) { return $idx; } if ($stripped === '' || str_starts_with($stripped, '//') || str_starts_with($stripped, '#![') || str_starts_with($stripped, '#[')) { continue; } return null; } return null; } /** @param list $lines */ private function consumeUseStatement(array $lines, int $startIdx): int { $braceDepth = 0; $i = $startIdx; $count = count($lines); while ($i < $count) { $line = $lines[$i]; $braceDepth += substr_count($line, '{') - substr_count($line, '}'); $done = $braceDepth <= 0 && str_ends_with(rtrim($line), ';'); $i++; if ($done) { return $i; } } return $i; } }