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の中でのアダプターを作る手間がいくらか省けます。