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
370
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
令和最新版手のひらコンピュータ
koba789
13
7.4k
パスタの技術
yusukebe
1
230
What's new in Adaptive Android development
fornewid
0
140
CLI ツールを Go ライブラリ として再実装する理由 / Why reimplement a CLI tool as a Go library
ktr_0731
3
1k
Understanding Kotlin Multiplatform
l2hyunwoo
0
250
バイブコーディング × 設計思考
nogu66
0
110
変化を楽しむエンジニアリング ~ いままでとこれから ~
murajun1978
0
710
DynamoDBは怖くない!〜テーブル設計の勘所とテスト戦略〜
hyamazaki
0
200
PHPカンファレンス関西2025 基調講演
sugimotokei
6
1.1k
GitHub Copilotの全体像と活用のヒント AI駆動開発の最初の一歩
74th
7
2.4k
大規模FlutterプロジェクトのCI実行時間を約8割削減した話
teamlab
PRO
0
460
新しいモバイルアプリ勉強会(仮)について
uetyo
1
250
Featured
See All Featured
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
131
19k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
34
6k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
126
53k
How to train your dragon (web standard)
notwaldorf
96
6.2k
The Art of Programming - Codeland 2020
erikaheidi
54
13k
Agile that works and the tools we love
rasmusluckow
329
21k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
10
1k
Practical Orchestrator
shlominoach
190
11k
Java REST API Framework Comparison - PWX 2021
mraible
33
8.8k
4 Signs Your Business is Dying
shpigford
184
22k
Statistics for Hackers
jakevdp
799
220k
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)