Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
PHP For Grown Ups
Search
linden3
April 14, 2015
Programming
3
350
PHP For Grown Ups
Slides of the talk as given at the PHPAmersfoort Meetup on April 14, 2015
linden3
April 14, 2015
Tweet
Share
Other Decks in Programming
See All in Programming
DevFest - Serverless 101 with Google Cloud Functions
tunmise
0
140
オニオンアーキテクチャを使って、 Unityと.NETでコードを共有する
soi013
0
370
Асинхронность неизбежна: как мы проектировали сервис уведомлений
lamodatech
0
1.3k
PSR-15 はあなたのための ものではない? - phpcon2024
myamagishi
0
400
ゼロからの、レトロゲームエンジンの作り方
tokujiros
3
1k
Fibonacci Function Gallery - Part 2
philipschwarz
PRO
0
210
Swiftコンパイラ超入門+async関数の仕組み
shiz
0
170
令和7年版 あなたが使ってよいフロントエンド機能とは
mugi_uno
10
5.1k
EC2からECSへ 念願のコンテナ移行と巨大レガシーPHPアプリケーションの再構築
sumiyae
3
580
混沌とした例外処理とエラー監視に秩序をもたらす
morihirok
13
2.2k
2025.01.17_Sansan × DMM.swift
riofujimon
2
540
Androidアプリのモジュール分割における:x:commonを考える
okuzawats
1
280
Featured
See All Featured
How STYLIGHT went responsive
nonsquared
96
5.3k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
Bash Introduction
62gerente
610
210k
4 Signs Your Business is Dying
shpigford
182
22k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.2k
Learning to Love Humans: Emotional Interface Design
aarron
274
40k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Optimising Largest Contentful Paint
csswizardry
33
3k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
132
33k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
Music & Morning Musume
bryan
46
6.3k
Transcript
PHP FOR GROWN-UPS
ANDREAS PHP DEVELOPER @ MIJNDOMEIN.NL
PHP HAS A BAD RAP (WHICH IT PARTLY DESERVES)
BUT YOU CAN STILL USE IT TO BUILD SOLID STUFF
(IF YOU KNOW HOW)
SO LET’S TALK ABOUT THE HOW
QUALITIES OF GOOD CODE
EASY TO CHANGE EASY TO UNDERSTAND EASY TO (RE)USE ~
HARD TO BREAK
“Always code as if the guy who ends up maintaining
your code will be a violent psychopath who knows where you live” - probably John Woods
SHY CODE
“Shy code - modules that don’t reveal anything unnecessary to
other modules and that don’t rely on other modules’ implementations” - The Pragmatic Programmer
ENCAPSULATION “MODULES THAT DON’T REVEAL ANYTHING UNNECESSARY TO OTHER MODULES”
$totalPrice = 0; foreach ($order->getItems() as $item) { $amount =
$item->getAmount(); $price = $item->getPrice(); $totalPrice += $amount * $price; } $totalPrice += $order->getShippingCosts();
$totalPrice = $order->getTotalPrice();
TELL, DON’T ASK
$order->applyDiscount($discountPercentage);
“[...] modules that don’t rely on other modules’ implementations”
interface EventDispatcher { public function dispatch(Event $event); }
public function __construct(EventDispatcher $eventDispatcher) { $this->eventDispatcher = $eventDispatcher }
class SymfonyEventDispatcher implements EventDispatcher { public function dispatch(Event $event) {
// Symfony implementation here } }
public function __construct(EventDispatcher $eventDispatcher) { $this->eventDispatcher = $eventDispatcher }
FROM THE PERSPECTIVE OF THE CONSUMER THE INTERFACE IS THE
REAL THING
“MATHEMATICS ABSTRACTION IS THE ART OF GIVING THE SAME NAME
TO DIFFERENT THINGS.” ~ HENRI POINCARÉ’S PROGRAMMER COUSIN
/** * before: */ public function search($searchTerm, $productCategory, $make, $color)
{ switch ($productType) { case ‘car’: // search cars case ‘boat’: // search boat // etc. } }
/** * after: */ public function search(SearchQuery $query) { $worker
= $this->getWorkerForQuery($query); /** @var SearchResults $results */ $results = $worker->process($query); return $results; }
”BUT... YOU JUST INTRODUCED COUPLING!”
“Figuring out if two people are married is easy. Figuring
out if they should be is hard.” - Michael Feathers
LEVELS OF ABSTRACTION
LOW LEVEL OF ABSTRACTION $statement = $database->prepare( “INSERT INTO `fish`(‘name’,
‘species’, ‘gender’, ‘tankId’) ” . “VALUES(?, ?, ?, ?)” ); $statement->execute(array(‘Nemo’, $speciesId, ‘M’, $tankId));
HIGH LEVEL OF ABSTRACTION $command = new IntroduceFishCommand($fish, $tank); $this->commandBus->execute($command);
LAYERED ARCHITECTURE
DATABASE QUERIES IN CONTROLLER CODE BUSINESS LOGIC IN VIEWS VIEW
LOGIC IN DOMAIN OBJECTS
MIXING LEVELS OF ABSTRACTION MAKES CODE HARDER TO UNDERSTAND
“THE RATIO OF TIME SPENT READING CODE VERSUS WRITING IS
WELL OVER 10 TO 1” ~ UNCLE BOB
“THERE ARE ONLY TWO HARD THINGS IN COMPUTER SCIENCE: CACHE
INVALIDATION AND NAMING THINGS” ~ PHIL KARLTON
// not: $light->setStatus(true); // but: $light->switchOn();
NAMES THAT LIE // neither of these is actually a
locale $this->locale = $locale->locale; // does more than it says public function getItem() { // write to disk }
EXTRACT METHOD // before: if (is_numeric($amount) && $amount > 0)
// after: if ($this->isValidAmount($amount))
VALUE OBJECTS $amount = new Amount($amount); // throws exception if
amount is invalid
CODE SAYS WHAT COMMENTS SAY WHY
// set the patient’s clinic $patient->setClinic($clinic); // to register a
patient, set the patient’s clinic $patient->setClinic($clinic);
GOOD NAMING AND GOOD ABSTRACTIONS BEAT GOOD COMMENTS
$clinic->registerPatient($patient);
PRINCIPLE OF LEAST ASTONISHMENT (MINIMIZE THE NUMBER OF WTFS PER
MINUTE)
“I REUSE CODE IF, AND ONLY IF, I NEVER NEED
TO LOOK AT THE SOURCE CODE” ~ UNCLE BOB
WELL-ABSTRACTED GOOD OUTWARD-FACING API DECOUPLED
NAMESPACES PREVENTING NAMING COLLISIONS SINCE PHP 5.3
COMPOSER
OPEN SOURCE VIA GITHUB/PACKAGIST PRIVATE REPOSITORIES IN COMPOSER.JSON TORAN PROXY
ADDED BONUS AUTOLOADING FOR INTERNAL CLASSES (THIS ALONE MAKES COMPOSER
WORTH USING)
PHPDOC DOCBLOCKS IDE USERS LOVE THIS
”SIMPLICITY IS PREREQUISITE FOR RELIABILITY.” ~ EDSGER DIJKSTRA
”Rely only on reliable things” - The Pragmatic Programmer
NOT A RELIABLE THING: THE PHP TYPE SYSTEM
if (! $amount) { // do something } // $amount
can actually be 0, “0”, “”, null or false for this to be true
if ($amount == 0) { // do something } //
$amount can now still be 0, “0” or false for this to be true
if ($amount === 0) { // do something } //
this will only evaluate to true when $amount is actually the number 0
“CRASH, DON’T TRASH” ~ THE PRAGMATIC PROGRAMMER
DO NOT PROGRAM BY COINCIDENCE
”TEST YOUR SOFTWARE, OR YOUR USERS WILL” ~ THE PRAGMATIC
PROGRAMMER
PHPUNIT PHPSPEC CODECEPTION BEHAT
“WHEN YOU AREN’T AFRAID TO CHANGE YOUR CODE, YOU WILL
CLEAN IT” ~ UNCLE BOB
LANGUAGE FEATURES TYPEHINTING VISIBILITY (PRIVATE BY DEFAULT) EXCEPTIONS
CLOSING NOTES
LEARNING ABOUT THIS STUFF IS EASY DOING IT RIGHT IS
HARD
“TO A MAN WITH A HAMMER, EVERYTHING LOOKS LIKE A
NAIL.” ~ ABRAHAM MASLOW
NONE OF THESE IDEAS ARE NEW (IN FACT, MOST ARE
PRETTY OLD)
“THE MORE I LEARN, THE MORE I REALIZE HOW MUCH
I DON’T KNOW” ~ ALBERT EINSTEIN
BOOKS Growing Object-Oriented Software, Guided By Tests The Pragmatic Programmer
Domain-Driven Design Patterns of Enterprise Application Architecture Clean Code
VIDEOS Models and Service Layers; Hemoglobin and Hobgoblins (https://www.youtube.com/watch?v=3uV3ngl1Z8g) Unbreakable
Domain Models (https://www.youtube.com/watch?v=ZJ63ltuwMaE) The Framework As An Implementation Detail (https://www.youtube.com/watch?v=0L_9NutiJlc)
PODCASTS Elephant in the Room (http://elephantintheroom.io)
QUESTIONS?
PLUG TIME WERKENBIJMIJNDOMEIN.NL
BONUS STAGE SOLID PRINCIPLES
“A CLASS SHOULD HAVE ONE, AND ONLY ONE, REASON TO
CHANGE.” ~ SOLID PRINCIPLE #1 (SINGLE RESPONSIBILITY PRINCIPLE)
“A CLASS SHOULD BE OPEN FOR EXTENSION, BUT CLOSED FOR
MODIFICATION” ~ SOLID PRINCIPLE #2 (OPEN-CLOSED PRINCIPLE)
”CHANGE WHAT A CLASS DOES, BUT NOT WHAT IT IS”
~ KONSTANTIN KUDRYASHOV
“SUBCLASSES MUST BE SUBSTITUTABLE FOR THEIR BASE CLASSES” ~ SOLID
PRINCIPLE #3 (LISKOV SUBSTITUTION PRINCIPLE)
”NEVER FORCE CLASSES TO IMPLEMENT METHODS THAT THEY DO NOT
USE” ~ SOLID PRINCIPLE #4 (INTERFACE SEGREGATION PRINCIPLE)
interface DoesAllTheThings { public function save(Soul $soul); public function addOneAndOne(One
$one, One $one); public function shave(Yak $yak); }
class DefaultCalculator implements Calculator { public function addOneAndOne(One $one, One
$one) { return new Two; } }
class DoesAllTheThings implements SoulSaver, Calculator, YakShaver { // can still
do all the things }
“DEPEND ON ABSTRACTIONS, NOT ON CONCRETIONS” ~ SOLID PRINCIPLE #5
(DEPENDENCY INVERSION PRINCIPLE)