Search code examples
laravelphpstan

How to avoid any phpstan errors with try / catch block in the end of the function?


On laravel 10 site running phpstan on method

    /**
     * Retrieve user getItemss related to getItems by $itemId
     *
     * param int $itemId - getItems id
     *
     * @return JsonResponse with collection of found data,
     *
     */
    public function getItems(int $itemId): JsonResponse
    {
        try {
            return response()->json([
                'data' => ItemResource::collection($this->itemRepository->getItems(id: $itemId))
            ], JsonResponse::HTTP_OK); // 200
        } catch (ModelNotFoundException $e) {
            return response()->json([
                'message' => 'Item # "' . $itemId . '" not found',
            ], JsonResponse::HTTP_INTERNAL_SERVER_ERROR);
        } catch (Exception $e) {
            \Log::info($e->getMessage());
        }
    }

But I have error pointing at try block line:

 Method App\Http\Controllers\Api\ItemController::getItems() should return Illuminate\Http\JsonResponse but return statement is missing.

Not sure what have I return under last catch and in the end of the function to avoid any phpstan errors ?

"laravel/framework": "^10.34.2",
"nunomaduro/larastan": "^2.6.4",

Thanks in advance!


Solution

  • Static typing means your function should always return the type you specified no matter what the input value or path it takes, in your case, your method getItems always expect to return JsonResponse regardless of its internal logic, the end result must be JsonResponse type,

    problem is when your 2nd catch block is hit, it does not return anything (just returns void)

    you could simply just do something like;

    public function getItems(int $itemId): JsonResponse {
        
        $message = 'Something wrong!';
        $code = JsonResponse::HTTP_INTERNAL_SERVER_ERROR;
    
        try {
            return response()->json([
                'data' => ItemResource::collection($this->itemRepository->getItems(id: $itemId))
            ], JsonResponse::HTTP_OK); 
    
        } catch (ModelNotFoundException $e) {
            $message = "Item # $itemId not found";
            $code = 404;
        } catch (Exception $e) {
            \Log::info($e->getMessage());
            $message =  $e->getMessage();
        }
    
        return response()->json( [
            'message' => $message 
        ], $code); 
    }
    

    To avoid unused variables

    public function getItems(int $itemId): JsonResponse {
    
        try {
            return response()->json([
                'data' => ItemResource::collection($this->itemRepository->getItems(id: $itemId))
            ], JsonResponse::HTTP_OK); 
    
        } catch (ModelNotFoundException $e) {
            $message = "Item # $itemId not found";
            $code = 404;
        } catch (Exception $e) {
            \Log::info($e->getMessage());
            $message =  $e->getMessage();
            $code = JsonResponse::HTTP_INTERNAL_SERVER_ERROR;
        }
    
        return response()->json( [
            'message' => $message 
        ], $code); 
    
    }
    

    another option with single return statement at the end of the function, and just mutating the variable inside try/catch block

    public function getItems(int $itemId): JsonResponse {
    
        $res = [ 'data' => null, 'message' => '' ];
        $code = JsonResponse::HTTP_INTERNAL_SERVER_ERROR;
    
        try {
            $res['data'] = ItemResource::collection($this->itemRepository->getItems(id: $itemId));
            $code = JsonResponse::HTTP_OK;
        } catch (ModelNotFoundException $e) {
            $res['message'] = "Item # $itemId not found";
            $code = 404;
        } catch (Exception $e) {
            \Log::info($e->getMessage());
            $res['message'] =  $e->getMessage();
        }
    
        return response()->json( $res, $code); 
        
    }
    

    or with each block has return statement no variables defined!

    public function getItems(int $itemId): JsonResponse {
    
        try {
            return response()->json([
                'data' => ItemResource::collection($this->itemRepository->getItems(id: $itemId))
            ], 200); 
        } catch (ModelNotFoundException $e) {
            return response()->json([ 'message' => "Item # $itemId not found" ], 404); 
        } catch (Exception $e) {
            return response()->json([ 'message' => $e->getMessage() ], 500); 
        }
        
    }