If I understand you correctly, you have a Validator
class that you want to dynamically implement different traits with. This isn't what traits were designed for.
Traits are for sharing common functionality across different classes without requiring them to extend the same class. Rather what you want to do is make each of your traits a stand-alone class that implements an interface. That you can then pass to your Validator
class.
This would look like this:
interface ValidatorMethod {
public function validate($input);
}
class NumberValidator implements ValidatorMethod {
public function validate($input) {
return is_numeric($input);
}
}
class IntegerValidator implements ValidatorMethod {
public function validate($input) {
return is_integer($input);
}
}
class Validator {
private $validators = [];
public function addValidator (ValidatorMethod $method) {
$validators[] = $method;
}
public function validate($input) {
foreach ($validators as $validator) {
if (!$validator->validate($input)) {
return false;
}
}
return true;
}
}
In this case, you would write individual tests for each of the ValidatorMethod
objects to verify that they pass correctly. As for the Validator
class, you would write tests passing in mock ValidatorMethod
that would pass and fail as needed. For example, if you wanted to have all the validators run regardless of the pass/fail of previous ones.
The tests would look something like so:
class ExampleValidatorMethodTest {
public function testValidatePass() {
$method = new NumberValidator();
$this->assertTrue($method->validate(1));
}
}
class ValidatorTest {
public function testSingleMethod() {
$method = $this->getMockBuilder('ValidatorMethod')
->getMock();
$input = 'foo';
$method->expects($this->once())
->with($input);
->will($this->returnValue(True));
$validator = new Validator();
$validator->addValidator($method);
$this->assertTrue($validator->validate($input));
}
public function testMultipleMethods() {
$method1 = $this->getMockBuilder('ValidatorMethod')
->getMock();
$method2 = $this->getMockBuilder('ValidatorMethod')
->getMock();
$input = 'foo';
$method1->expects($this->once())
->with($input);
->will($this->returnValue(True));
$method2->expects($this->once())
->with($input);
->will($this->returnValue(True));
$validator = new Validator();
$validator->addValidator($method1);
$validator->addValidator($method2);
$this->assertTrue($validator->validate($input));
}
}
There are some optimizations that can be done in the tests to make the code simpler but the examples are to just give an idea of what you are looking to do.