Hello there!
Who am I?
Yoan-Alexander Grigorov
PHP developer (with pride!)
Software Engineer
Critic
Design Patterns adventurer
SOLID design?
Imagine code as a painting
Well... maybe not this one in particular!
Now that's better!
Nothing against modern art, but...
Code should be easy to recognize!
How a project starts:
Several months later...
What is going wrong?
● Frequently logic changes are made with “hacks”
without refactoring
● Lack of knowledge on … stuff
● Lack of discipline
SOLID? What's that?
● Single responsibility
● Open-closed
● Liskov substitution
● Interface segregation
● Dependency inversion
What SOLID can't do?
● Cure ebola
● Explain why is there PHP 7 coming out, but no PHP
6?!?!?
● Make Bulgarian politicians suck less
Let's break it down!
Single responsibility principle
Every variable, class, function, etc. should have a single
responsibility, described in it's name (if any).
Single responsibility principle
Basically it's bad if we have a function (or class)
that does more then what it's name says.
Single responsibility principle
Here is one real-life example how bad it is to break
this rule:
Single responsibility principle
Hidden features can have unexpected effects
Single responsibility principle
● Bad code example:
<?php
class InsurancePDFCreator {
// … some code
public function createPDFContents(Policy $policy);
public function downloadInsuranceCompanyLogos();
}
Single responsibility principle
● Good code example:
<?php
class InsurancePDFCreator {
// … some code
public function createPDFContents(Policy $policy);
}
// somewhere else
class InsuranceCompanyLogosDownloader {
public function download();
}
Conclusion
● Define your desired contexts carefully
● Make sure that there is only one responsibility for a
operation, class, method, module, etc.
● If you need to have a more abstract operations that
combine several stuff, find for them more abstract
names.
● And... Single Responsibility Principle is not
enough
Interface Segregation Principle
No system (module, class) should be required to depend
on methods it does not use.
Interface Segregation Principle
This is pretty much an extension to the SRP
Interface Segregation Principle
● Avoid having classes of “mothership” type
● Avoid the “Manager” type classes
Interface Segregation Principle
● Imagine this code:
<?php
class UsersManager {
public function createUser($username, $email);
public function deleteUserPicture($userId);
public function notifyUser($userId, $msg);
}
Interface Segregation Principle
It's bad because:
● It's provides a general-purpose interface
● When you include this class, you usually call one of
those methods
Interface Segregation Principle
The good way to do it:
● Use a set of client-specific classes (interfaces)
instead of one general-purpose interface
● Be more specific in your context
Interface Segregation Principle
Good example:
<?php
class UserCreator {}
class UserPictureDeleter {}
class UserNotifier {}
Conclusion
● Is extension to the Single Responsibility Principle
● Favored usage of client-specific interfaces, rather
then one general-purpose (mothership) interface
Open-Closed Principle
Classes should be opened for extension, but closed for
modification
Open-Closed Principle
<?php
class ProductDiscountCalculator {
public function calculateDiscount(Product $product)
{
// some serious business here for $discountRate
return $product->getPrice() / $discountRate;
}
}
Open-Closed Principle
<?php
// somewhere else a naughty developer writes this:
class MyProductDiscountCalc extends ProductDiscountCalculator {
public function calculateDiscount(Product $product)
{
// Hardcoded discount here
return 300;
}
}
Open-Closed Principle
Why is this so bad?
● ProductDiscountCalculator is not an interface, but a
specific class
● We can push into usage it's replacement
● The code relies on ProductDiscountCalculator, but
it's children are changing the behavior and this is
bad
Open-Closed Principle
REMEMBER!
● Modifying (overriding) existing methods is bad
● Extending them (e.g. add new methods or implement
abstract methods) is good
Open-Closed Principle
“But who is using specific types anyways? Can't we just use
interfaces?”
- Yes, that's why we should look at the next principles.
Open-Closed Principle
I bet you are puzzled now!
Don't be afraid, open-closed principle is used best
with his fellow brother the Liskov Substitution
principle!
Open-Closed Principle
● It bit better way to do it:
class MyProductDiscountCalc extends ProductDiscountCalculator {
public function myCalculateDiscount(Product $product)
{
// Hardcoded discount here
return 300;
}
}
Open-Closed Principle
Not the best way, but Open-Closed principle works
best with his friends from SOLID!
Liskov Substitution Principle
Subtypes could replace their parents, and the program
should have the same behaviour.
Liskov Substitution Principle
Basically we must make sure that new derived
classes are extending the base classes without
changing their behavior. It's that easy.
???
Liskov Substitution Principle
As ridiculous as it may sound I'll explain you what
it's the meaning behind this.
Liskov Substitution Principle
Let's remember the previous example:
class ProductDiscountCalculator {
public function calculateDiscount(Product $product);
}
class MyProductDiscountCalculator ...
public function myCalculateDiscount(Product $product);
}
Liskov Substitution Principle
How do you know which is which?
<?php
if ($calc instanceof ProductDiscountCalculator) {
$calc->calculateDiscount($product);
}
if ($calc instanceof MyProductDiscountCalculator) {
$calc->myCalculateDiscount($product);
}
Liskov Substitution Principle
I suppose you don't do such horrible things like
type checking
Liskov Substitution Principle
● One solution is to use abstract method:
<?php
abstract class AbstractDiscountCalc {
public function calculateDiscount(Product $product) {
return $this->getDiscountForProduct($product);
}
abstract protected function
getDiscountForProduct(Product $product);
}
Liskov Substitution Principle
<?php
class DefaultProductDiscountCalc extends AbstractDiscountCalc
{
protected function getDiscountForProduct(Product $product)
{
// our main algorithm for $discountRate
return $product->getPrice / $discountRate;
}
}
Liskov Substitution Principle
<?php
class MyProductDiscountCalc extends AbstractDiscountCalc
{
protected function getDiscountForProduct(Product $product)
{
// Fixed discount
return 300;
}
}
Liskov Substitution Principle
Still not the best way, but much better!
Dependency inversion principle
One system should depend on abstractions (interfaces)
rather then concretions
Dependency inversion principle
Remember Dependency Injection?
Pretty much DI is following the Dependency
Inversion principle
Dependency inversion principle
● So our previous example would use an interface:
<?php
interface DiscountCalculator {
public function calculateDiscount(Product $product);
}
Dependency inversion principle
This way we depend on interfaces, not on specific
classes (which is the main idea behind interfaces)
Dependency inversion principle
You can still define a mid-level abstract class to
implement just some parts of the logic.
SOLID and others
● Use SOLID with TDD
● You can make DDD even better with SOLID
● SOLID principles are universal
Thank you for listening!
● joan.grigorov@gmail.com
● @YoanDev
● http://bgscripts.com

SOLID design