What are the best practices for structuring and managing classes in PHP frameworks like Slim to avoid reliance on a single class like "Slim\App"?

When structuring and managing classes in PHP frameworks like Slim, it's important to avoid heavy reliance on a single class like "Slim\App" to prevent tight coupling and improve code maintainability. One way to achieve this is by implementing dependency injection to pass necessary dependencies into classes rather than hardcoding them. This allows for better separation of concerns and easier testing of individual components.

// Example of implementing dependency injection in a Slim application

use Slim\App;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;

class UserController {
    private $app;

    public function __construct(App $app) {
        $this->app = $app;
    }

    public function getUsers(Request $request, Response $response, array $args) {
        // Logic to fetch users data
        $users = [];

        // Return response
        return $this->app->getResponseFactory()->createResponse()->withJson($users);
    }
}

// Usage in routes
$app->get('/users', function (Request $request, Response $response, $args) use ($app) {
    $userController = new UserController($app);
    return $userController->getUsers($request, $response, $args);
});