Laravelはコントローラが何を返そうがサーバがクライアントにレスポンスを返せる様にがんばります。暗黙の型変換を行うPHPの鑑ですね。
Laravelはミドルウェア、ルートバインディングをなんやかんや通って、コントローラのメソッドを実行、返り値をレスポンスにします。
肝心のレスポンスはvendor/laravel/framework/src/Illuminate/Routing/Router.phpのtoResponseメソッドで整形されます。
/**
* Static version of prepareResponse.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param mixed $response
* @return \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*/
public static function toResponse($request, $response)
{
if ($response instanceof Responsable) {
$response = $response->toResponse($request);
}
if ($response instanceof PsrResponseInterface) {
$response = (new HttpFoundationFactory)->createResponse($response);
} elseif ($response instanceof Model && $response->wasRecentlyCreated) {
$response = new JsonResponse($response, 201);
} elseif (! $response instanceof SymfonyResponse &&
($response instanceof Arrayable ||
$response instanceof Jsonable ||
$response instanceof ArrayObject ||
$response instanceof JsonSerializable ||
is_array($response))) {
$response = new JsonResponse($response);
} elseif (! $response instanceof SymfonyResponse) {
$response = new Response($response);
}
if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) {
$response->setNotModified();
}
return $response->prepare($request);
}
$responseの型を判定し、適したメソッドを呼ぶか、適したオブジェクトに変換してます。見るからにレスポンスにできるものはレスポンスにする、という貪欲さが見えます。とりあえず特長的なのは普通にhogehogeResponseという型で判定していない部分である次の条件文です。
} elseif (! $response instanceof SymfonyResponse &&
($response instanceof Arrayable ||
$response instanceof Jsonable ||
$response instanceof ArrayObject ||
$response instanceof JsonSerializable ||
is_array($response))) {
$response = new JsonResponse($response);
} elseif (! $response instanceof SymfonyResponse) {
とりあえずjsonにできるならなんでもいい、arrayでもいい、という条件文です。これのおかげでControllerの中でのアダプターを作る手間がいくらか省けます。