Validating a model that requires database access Let's say I have this User model:

class User
{
    public $id;
    public $email;
    public $password;
    public $errors;

    public function isValid()
    {
        if (strpos($this-&gt;email, '@') === false) {
            $this-&gt;errors['email'] = 'Please enter an email address';
        }
        if (!$this-&gt;password) {
            $this-&gt;errors['password'] = 'Please enter a password';
        } elseif (strlen($this-&gt;password) &lt; 4) {
            $this-&gt;errors['password'] = 'Please enter a longer password';
        }

        return !$this-&gt;errors;
    }
}


And let's say I have this UserDAO for retrieving, adding, updating, and deleting users:

class UserDAO
{
    protected $conn;
    protected $logger;

    public function __construct(PDO $dbh, Logger $logger) 
    {
        $this-&gt;dbh = $dbh;
        $this-&gt;logger = $logger;
    }

    public function getUsers() 
    {
        $rows = null;
        try {
            $rows = $this-&gt;dbh-&gt;query("SELECT * FROM users")-&gt;fetchAll();
        } catch (PDOException $e) {
            $this-&gt;logger-&gt;log($e-&gt;getMessage(), __METHOD__);
        }
        return $rows;
    }

    public function getUserById($id) 
    {
        $row = null;
        try {
            $sth = $this-&gt;dbh-&gt;prepare("SELECT * FROM users WHERE id = ?");
            $sth-&gt;execute(array($id));
            $row = $sth-&gt;fetchObject('User');
        } catch (PDOException $e) {
            $this-&gt;logger-&gt;log($e-&gt;getMessage(), __METHOD__);
        }
        return $row;
    }

    public function addUser(User &amp;$user) 
    {
        $success = false;
        try {
            $sth = $this-&gt;dbh-&gt;prepare("
                INSERT INTO users (email, password) VALUES (?, ?)
            ");
            $sth-&gt;execute(array($user-&gt;email, $user-&gt;password));
            if ($success = (bool) $sth-&gt;rowCount()) {
                $user-&gt;id = $this-&gt;dbh-&gt;lastInsertId();
            }
        } catch (PDOException $e) {
            $this-&gt;logger-&gt;log($e-&gt;getMessage(), __METHOD__);
        }
        return $success;
    }

    public function updateUser(User $user) 
    {
        // ...
    }

    public function deleteUser($id) 
    {
        // ...
    }

    public function isEmailUnique($email) 
    {
        $count = 0;
        try {
            $sth = $this-&gt;dbh-&gt;prepare("SELECT COUNT(id) FROM users WHERE email = LOWER(?)");
            $sth-&gt;execute(array($email));
            $count = $sth-&gt;fetchColumn();
        } catch (PDOException $e) {
            $this-&gt;logger-&gt;log($e-&gt;getMessage(), __METHOD__);
        }
        return !$count;
    }
}


When I process a form, I typically do something like this:

// ...

$userDAO = new UserDAO($dbh, $logger);
$user = new User();
$user-&gt;email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$user-&gt;password = filter_input(INPUT_POST, 'password');
// validate user
if ($user-&gt;isValid()) {
    // check if email address is unique (SO UGLY!)
    if ($userDAO-&gt;isEmailUnique($user-&gt;email)) {
        $user-&gt;errors['email'] = 'Please use a different email address';
    }
    // save user
    if ($user-&gt;addUser($user)) {
        // ...
    } else {
        // ...
    }
} else {
    // do something with $user-&gt;errors
}


This works great for simple cases, but how can I improve this? In particular, how can I do validations that require database access? For example, if I wanted to check that the email is unique and make it part of my validation, what would be a better way of doing this?
Best approach would be to have another Object to do the validation based on specific configuration.

Your User should NOT be responsible for validating itself, neither should the DAO.
Validation is a specific task and should be handled by a specific Class.

Example of this approach would be something like this (omitiong interfaces for brevity):

validation class

Class Validator 
{
   protected $errors = [];

   public function __construct(DaoInterface $daoDependency, $otherDependency)
   {
      //...
   }

   public function validate($object, array $rules) 
   {
       foreach ($rules as $rule)
       {
           $propertyName = $rule['property'];
           if (!$this-&gt;isValidateProperty($object, $propertyName, $rule['config'])) {
               $this-&gt;errors[$object-&gt;$propertyName] = 'is invalid ' . $rule['message'];
           }
       }
   }

   public function isValid()
   {
       return (bool)count($this-&gt;errors);
   }

   public function getErrors()
   {
       return $this-&gt;errors;
   }

   protected function isValidProperty($object, $propertyName, $ruleConfig)
   {
       // $ruleConfig should have information about what validation you want to use and relevant validation should be executed base on it (it can separate objects etc)
       if (!property_exists($object, $propertyName)
          throw new MissingPropertyException();


       if (isset($ruleConfig['email-unique-in-db') {
           if ($daoDependecny-&gt;emailExists($object-&gt;$propertyName) {
               return false;
           }
       }
       if (isset($ruleConfig['email-is-valid') {
           return (bool)strpos($object-&gt;$propertyName, '@');               
       }
       // ... etc but better with objects for each validation type.
   }
}


usage

$userDAO = new UserDAO($dbh, $logger);
$user = new User();
$user-&gt;email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$user-&gt;password = filter_input(INPUT_POST, 'password');

// get your validation rules
// you can have them stored in other object, plain array, yml whatever you like. for instance $rules = new UserConstrains(); or
$rules['config] = [
  'email' =&gt; [
      'email-unique-in-db',
      'email-is-valid'
  ],
  'otherfield' =&gt; [
      'callback' =&gt; ['someCallbackFunction']
  ]
];

// create validator
$validator = new Validator($userDao, $otherDepenency);
$validator-&gt;validate($user, $rules);
// validate user

if (validator-&gt;isValid()) {
   // .. do stuff
} else {
   // do something with $user-&gt;errors
}


The separation of concerns is the most important thing here.
You can extend/decorate the validator class for specific use cases

Also if would recommend using some specialized validation library for this task for instance symfony2 validation component can be used stand alone: http://symfony.com/doc/current/book/validation.html