How can dependency injection be utilized to improve the separation of concerns between models and data access logic in PHP?

Dependency injection can be utilized to improve the separation of concerns between models and data access logic in PHP by injecting the data access object (such as a database connection) into the model class instead of the model class creating or managing its own data access object. This allows for better encapsulation and modularity, making the code more maintainable and testable.

// Data Access Object
class Database {
    public function query($sql) {
        // Database query logic here
    }
}

// Model class
class User {
    private $db;

    public function __construct(Database $db) {
        $this->db = $db;
    }

    public function getUserById($id) {
        $sql = "SELECT * FROM users WHERE id = $id";
        return $this->db->query($sql);
    }
}

// Usage
$db = new Database();
$user = new User($db);
$userData = $user->getUserById(1);