setDescription('Starts a development server') ->setHelp('You can provide an optional host and port, for the development server.') ->addOption('host', null, InputOption::VALUE_REQUIRED) ->addOption('port', null, InputOption::VALUE_REQUIRED); } protected function execute(InputInterface $input, OutputInterface $output): int { $base = app('paths.base'); $host = $input->getOption('host') ?: env('APP_HOST', '127.0.0.1'); $port = $input->getOption('port') ?: env('APP_PORT', '8000'); if (empty($host) || empty($port)) { throw new InvalidArgumentException('APP_HOST and APP_PORT both need values'); } $this->handleSignals(); $this->startProcess($host, $port, $base, $output); return Command::SUCCESS; } private function command(string $host, string $port, string $base): array { $separator = DIRECTORY_SEPARATOR; return [ PHP_BINARY, "-S", "{$host}:{$port}", "{$base}{$separator}server.php", ]; } private function handleSignals(): void { pcntl_async_signals(true); pcntl_signal(SIGTERM, function($signal) { if ($signal === SIGTERM) { $this->process->signal(SIGKILL); exit; } }); } private function startProcess(string $host, string $port, string $base, OutputInterface $output): void { $this->process = new Process($this->command($host, $port, $base), $base); $this->process->setTimeout(PHP_INT_MAX); $this->process->start(function($type, $buffer) use ($output) { $output->write("{$buffer}"); }); $output->writeln("Serving requests at http://{$host}:{$port}"); $this->process->wait(); } }