Open
Description
Take following example:
class Counter
{
private $count = 0;
public function increment() : void {
$this->count += 1;
}
public function count() : int {
return $this->count;
}
}
class LoggingCounter extends Counter
{
private $logger;
private $originalCounter;
public function __construct(Logger $logger, Counter $originalCounter)
{
$this->logger = $logger;
$this->originalCounter = $originalCounter;
}
public function increment() : void {
$this->logger->log('increment');
$this->originalCounter->increment();
}
}
If Counter
is modified to add an increment2
method, LoggingCounter
fails (this is partly described in my article "When to declare Classes Final" ).
class Counter
{
private $count = 0;
public function increment() : void {
$this->count += 1;
}
public function increment2() : void {
$this->count += 2;
}
public function count() : int {
return $this->count;
}
}
Here's a test to show that:
class LoggingCounterTest extends TestCase
{
public function incrementAndIncrement2() : void
{
$counter = new LoggingCounter($this->createMock(Logger::class), new Counter());
$counter->increment();
$counter->increment2();
self::assertSame(3, $counter->count());
}
}
This is because decorators require an update for each parent class public API change. Therefore, we should mark any addition of methods to an open class as a BC break.
Activity