is_file($d . '/config.php') && is_file($d . '/vendor/autoload.php') && is_file($d . '/src/Config.php'); for ($dir = dirname(__DIR__), $i = 0; $i < 4; $i++) { foreach ([$dir . '/' . APP_PRIVATE_DIR, $dir] as $candidate) { if ($isAppRoot($candidate)) return $candidate; } if (dirname($dir) === $dir) break; $dir = dirname($dir); } fwrite(STDERR, "config.php / vendor/autoload.php / src/Config.php 를 찾지 못했습니다.\n"); exit(1); } /** @return array{0: \App\Config, 1: \PDO} */ function tool_boot(): array { $root = tool_app_root(); require_once $root . '/vendor/autoload.php'; $cfg = \App\Config::fromArray(require $root . '/config.php'); return [$cfg, \App\Db\Database::connect($cfg)]; } /** Parse `--key=value` / `--flag` argv into an array. */ function tool_args(array $argv): array { $out = []; foreach (array_slice($argv, 1) as $a) { if (!str_starts_with($a, '--')) continue; $a = substr($a, 2); if (str_contains($a, '=')) { [$k, $v] = explode('=', $a, 2); $out[$k] = $v; } else { $out[$a] = true; } } return $out; } /** true when the DSN targets sqlite — a few statements differ and the tools must not guess. */ function tool_is_sqlite(\PDO $pdo): bool { return $pdo->getAttribute(\PDO::ATTR_DRIVER_NAME) === 'sqlite'; }