Aliasing `HttpServer` with `Server` fails with an optimized autoloader
bzikarsky opened this issue · comments
Note: This discussion started in/relates to amphp/http-server-static-content#13
When using http-server-static-content
, amphp/http-server-form-parser
and amphp/http-server-router
in production we noticed errors after an upgrade of amphp/http-server
to a recent version:
Fatal error: Could not check compatibility between TestObserver::onStart(Amp\Http\Server\Server $server): Amp\Promise and Amp\Http\Server\ServerObserver::onStart(Amp\Http\Server\HttpServer $server): Amp\Promise, because class Amp\Http\Server\Server is not available in <path>
This issue was a mystery first, I wrote a minimum example that seemed to work fine (tested in root-dir of http-server 4.5.5 with PHP 7.4.16, with a standard composer install
):
<?php
declare(strict_types=1);
use Amp\Http\Server\HttpServer;
use Amp\Http\Server\RequestHandler\CallableRequestHandler;
use Amp\Http\Server\Response;
use Amp\Http\Server\Server;
use Amp\Http\Server\ServerObserver;
use Amp\Http\Status;
use Amp\Loop;
use Amp\Promise;
use Amp\Success;
use Psr\Log\NullLogger;
require \dirname(__DIR__) . "/vendor/autoload.php";
class TestObserver implements ServerObserver {
public function onStart(Server $server): Promise
{
echo "started\n";
return new Success();
}
public function onStop(Server $server): Promise
{
echo "stopped\n";
return new Success();
}
}
$testObserver = new TestObserver();
Loop::run(function () use ($testObserver) {
$socket = \Amp\Socket\Server::listen("tcp://127.0.0.1:0");
$server = new HttpServer([$socket], new CallableRequestHandler(function () {
return new Response(Status::OK);
}), new NullLogger());
$server->attach($testObserver);
yield $server->start();
yield $server->stop();
});
It worked, and this seemed strange to me. But in the end, it also didn't fail on us in CI. After some more analysis, I was able to narrow it down to composer autoloader optimizations: When I run composer install --optimize-autoloader --classmap-authoritative
(as we do in our build process), I can reproduce it. Which makes sense, because the Server
class is essentially defined at runtime with a class_alias
.
It's possible to fix this in multiple ways, described in more detail here and here. For simplicity's sake, I suggest adding "src/Server.php"
to the "files"
section of the composer autoloader definition.
Yes, having it in src/Server.php
is obviously wrong. I think we can just move it to src/functions.php
, which is always loaded anyway. But I'd be fine with loading src/Server.php
as well. Do you want to submit a PR?
PR is open, a timely tag would be very appreciated, so I can remove the hotfix in our codebase. :-)
I failed to pull before tagging, but v2.1.2
includes your fix, thanks!