Просто добавьте к ответу @Ezku (+1, все, что я бы сказал тоже), чтобы окончательный код мог выглядеть примерно так (используя Внедрение зависимости )
public function __construct(Memcached $mem, DatabaseObject $db) {
$this->mem = $mem;
$this->db = $db;
}
public function getSomeData() {
$key = "SomeMemcacheKey";
$cache = $this->mem;
$results = $cache->get($key);
if (!$results) {
$database = $this->db;
$sql = "SELECT * from someDatabase.someTable";
$results = $database->query($sql);
$cache->set($key, $results);
}
return $results;
}
С этим действительно легко создавать фиктивные объекты и передавать их в код.
Есть несколько причин, по которым вы можете захотеть сделать это (кроме создания тестируемого кода). На этот раз это делает ваш код гораздо более открытым для изменения (требуется другой db? Pass в другом объекте db вместо изменения кода в вашем DatabaseObject.
В этом блоге рассказывается о том, почему статические методы плохи, но использование оператора "new" в вашем коде - это почти то же самое, что сказать $x = StaticStuff::getObject();
, поэтому оно применимо и здесь.
Другая ссылка может быть такой: Почему синглтоны плохо подходят для тестируемого кода , потому что он затрагивает те же точки.
Если у вас уже написано больше кода, есть несколько способов реализовать эту идею, не меняя все сразу.
Необязательное внедрение зависимости, например:
public function __construct(Memcached $mem = null, DatabaseObject $db = null) {
if($mem === null) { $mem = new DefaultCacheStuff(); }
if($db === null) { $db = new DefaultDbStuff(); }
$this->mem = $mem;
$this->db = $db;
}
public function getSomeData() {
$key = "SomeMemcacheKey";
$cache = $this->mem;
$results = $cache->get($key);
if (!$results) {
$database = $this->db;
$sql = "SELECT * from someDatabase.someTable";
$results = $database->query($sql);
$cache->set($key, $results);
}
return $results;
}
или с использованием «инъекции в сеттер»:
public function __construct(Memcached $mem = null, DatabaseObject $db = null) {
$this->mem = new DefaultCacheStuff();
$this->db = new DefaultDbStuff();
}
public function setDatabaseObject(DatabaseObject $db) {
$this->db = $db;
}
public function setDatabaseObject(Memcached $mem) {
$this->mem = $mem;
}
public function getSomeData() {
$key = "SomeMemcacheKey";
$cache = $this->mem;
$results = $cache->get($key);
if (!$results) {
$database = $this->db;
$sql = "SELECT * from someDatabase.someTable";
$results = $database->query($sql);
$cache->set($key, $results);
}
return $results;
}
Кроме того, есть вещи, называемые dependency injection containers
, которые позволяют убрать все создаваемые возражения и вытащить все из этого контейнера, но поскольку это делает тестирование немного сложнее (imho), и это поможет вам только в том случае, если все сделано действительно хорошо. не предложил бы начинать с одного, а просто использовать обычное «внедрение зависимостей» для создания тестируемого кода.