SlideShare ist ein Scribd-Unternehmen logo
1 von 62
Downloaden Sie, um offline zu lesen
Object Calisthenics
Adapted for PHP
A little about me
●
●
●
●
●
●
●

Bedford, VA
Radford University
9+ Years PHP
8+ Years @ DE
Hampton Roads PHP
Comics
Every Hulk Issue
Object Calisthenics
●
●
●
●
●
●

First introduced by Jeff Bay
Based on Java Development
Guidelines Not Rules
Difficulty varies
Write Better Code
Adapted for PHP
Object Calisthenics #1

“Only one level of indentation per method”
#1 Only one level of indentation
public function validate(array $products)
{
$requiredFields = ['price', 'name', 'description'];
$valid = true;
foreach ($products as $rawProduct) {
$fields = array_keys($rawProduct);
foreach ($requiredFields as $requiredField) {
if (!in_array($requiredField, $fields)) {
$valid = false;
}
}
}
return $valid;
}
#1 Only one level of indentation
public function validate(array $products)
{
$requiredFields = ['price', 'name', 'description'];
$valid = true;

0

foreach ($products as $rawProduct) {

1

$fields = array_keys($rawProduct);
foreach ($requiredFields as $requiredField) {

2 if (!in_array($requiredField, $fields)) {
3 $valid = false;
}
}
}
return $valid;
}
#1 Only one level of indentation
public function validate(array $products)
{
$requiredFields = ['price', 'name', 'description'];
$valid = true;
foreach ($products as $rawProduct) {
$valid = $valid && $this->validateSingle($rawProduct, $requiredFields);
}
return $valid;
}
public function validateSingle(array $product, array $requiredFields)
{
$fields = array_keys($product);
return count(array_diff($requiredFields, $fields)) == 0;
}
#1 Only one level of indentation
Key Benefits
● Encourages Single Responsibility
● Increase Re-use
Object Calisthenics #2

“Do not use the ‘else’ keyword”
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
} elseif (is_string($exception)) {
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
} else {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
} elseif (is_string($exception)) {
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
} else {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
} elseif (is_string($exception)) {
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
} else {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {

return early

throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
} elseif (is_string($exception)) {
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
} else {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
}
if (is_string($exception)) {
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
} else {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");

reverse condition

}
if (is_string($exception)) {
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
} else {

throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
}
if (!is_string($exception)) {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
}
if (!is_string($exception)) {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
if ($exceptionArgs === null) {
throw new Exception($exception);
} else {
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
}

return early
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
}
if (!is_string($exception)) {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
if ($exceptionArgs === null) {
throw new Exception($exception);
}
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
#2 Do not use the ‘else’ keyword
public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null)
{
if ($valueToEnsure === $valueToCheck) {
return $valueToCheck;
}
if ($exception === null) {
throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'");
}
if (!is_string($exception)) {
throw new InvalidArgumentException('$exception was not a string, Exception or null');
}
if ($exceptionArgs === null) {
throw new Exception($exception);
}
if (array_key_exists($exception, self::$_exceptionAliases)) {
$exception = self::$_exceptionAliases[$exception];
}
$reflectionClass = new ReflectionClass($exception);
throw $reflectionClass->newInstanceArgs($exceptionArgs);
}
#2 Do not use the ‘else’ keyword
Key Benefits
● Helps avoid code duplication
● Easier to read (single path)
● Reduces cyclomatic complexity
Object Calisthenics #3

“Wrap all primitives and Strings”
*If there is behavior
#3 Wrap primitives and Strings
class Item
{
final public static function find($id)
{
if (!is_string($id) || trim($id) == '')
throw new InvalidArgumentException('$id must be a non-empty string');
// do find ...
}
final public static function create($id, array $data)
{
if (!is_string($id) || trim($id) == '')
throw new InvalidArgumentException('$id must be a non-empty string');
// do create ...
}
}
#3 Wrap primitives and Strings
class Item
{
final public static function find($id)
{

validation with
id

if (!is_string($id) || trim($id) == '')
throw new InvalidArgumentException('$id must be a non-empty string');
// do find ...
}
final public static function create($id, array $data)

validation with
id

{
if (!is_string($id) || trim($id) == '')
throw new InvalidArgumentException('$id must be a non-empty string');
// do create ...
}
}
#3 Wrap primitives and Strings
class Id
{
private $value;
final public function __construct($value)
{
if (!is_string($value) || trim($value) == '')
throw new InvalidArgumentException('$value must be a non-empty string');

$this->value = $value;
}
final public function getValue()
{
return $this->value;
}
}
#3 Wrap primitives and Strings
class Id
{
private $value;
final public function __construct($value)

validation
encapsulated in
constructor

{
if (!is_string($value) || trim($value) == '')
throw new InvalidArgumentException('$value must be a non-empty string');

$this->value = $value;
}
final public function getValue()
{
return $this->value;
}
}
#3 Wrap primitives and Strings
class Item
{
final public static function find(Id $id)
{
// do find ...
}

final public static function create(Id $id, array $data)
{
// do create ...
}
}
#3 Wrap primitives and Strings
class Item
{
final public static function find(Id $id)
{
// do find ...
}

final public static function create(Id $id, array $data)
{
// do create ...
}
}

$id now guaranteed to
be valid.
#3 Wrap primitives and Strings
Warning!!!
Using large amounts of objects will increase
the memory footprint of PHP.
#3 Wrap primitives and Strings
Key Benefits
● Type Hinting
● Encapsulation of operations
Object Calisthenics #4

“Use first class collections”
#4 Use first class collections
A class that contains a collection should
contain no other instance variables.
#4 Use first class collections
class Items implements Iterator
{
private $items = [];
final public function add(Item $item)
{
// do add ...
}
final public function filter(array $filters)
{
// do filter ...
}
final public function merge(Items $items)
{
// do merge ...
}
}
#4 Use first class collections
Key Benefits
● Implements collection operations
● Uses SPL interfaces
● Easier to merge collections and not worry
about member behavior in them
Object Calisthenics #5

“One object operator per line”
#5 One object operator per line

$this->manager->getConfig()->getSegment()->setName('foo');
#5 One object operator per line
Properties are harder
to mock

$this->manager->getConfig()->getSegment()->setName('foo');
#5 One object operator per line
Properties are harder
to mock

$this->manager->getConfig()->getSegment()->setName('foo');

Previous call could
return null
#5 One object operator per line
Properties are harder
to mock

May indicate feature
envy

$this->manager->getConfig()->getSegment()->setName('foo');

Previous call could
return null
#5 One object operator per line
Key Benefits
● Readability
● Easier Testing
● Easier to Debug
Object Calisthenics #6

“Do not abbreviate”
#6 Do not abbreviate
public function getPage() { ... }
public function startProcess() { ... }
$smp->process("index");
#6 Do not abbreviate
get what page
from where?
public function getPage() { ... }
public function startProcess() { ... }
$smp->process("index");
#6 Do not abbreviate
get from where?

public function getPage() { ... }
public function startProcess() { ... }
$smp->process("index");

???
#6 Do not abbreviate
get what page
from where?
public function getPage() { ... }

Use clearer names:
renderHomePage()
downloadHomePage()

public function startProcess() { ... }
$smp->process("index");

???
#6 Do not abbreviate
get what page
from where?
public function getPage() { ... }

Use clearer names:
renderHomePage()
downloadHomePage()

public function startProcess() { ... }
$smp->process("index");

???

Use a thesaurus:
fork, create, begin, open
#6 Do not abbreviate
get what page
from where?
public function getPage() { ... }

Use clearer names:
renderHomePage()
downloadHomePage()

public function startProcess() { ... }
$smp->process("index");

???

Use a thesaurus:
fork, create, begin, open

Easy understanding,
complete scope:
$siteMapProcessor
#6 Do not abbreviate
Key Benefits
● Clearer communication and maintainability
● Indicates underlying problems
Object Calisthenics #7

“Keep classes small”
#7 Keep classes small
200 lines per class (including docblocks)
10 methods per class
15 classes per namespace (folder)
#7 Keep classes small
Key Benefits
● Single Responsibility
● Objective and clear methods
● Slimmer namespaces
Object Calisthenics #8

“Limit the number of instance variables in a
class”
#8 Limit instance variables in a class
class Client
{
private $_adapter;
private $_cache;
private $_logger;

// ...
}

Limit: 2 - 5
#8 Limit instance variables in a class
Key Benefits
● Shorter dependency list
● Easier Mocking for unit tests
Object Calisthenics #9

“Use getters/setters”
#9 Use Getters and Setters
class Tally
{
public $total = 0;

public function add($amount)
{
$this->total += $amount;
}
}

$tally = new Tally();
$tally->add(1);
// some other code ...
$tally->total = -1;
// some other code ...
$tally->add(1);
echo $tally->total . PHP_EOL;
#9 Use Getters and Setters
class Tally
{
public $total = 0;

public function add($amount)
{
$this->total += $amount
}
}

$tally = new Tally();
$tally->add(1);
// some other code ...
$tally->total = -1
// some other code ...
$tally->add(1);
echo $tally->total . PHP_EOL;

total can be changed without
this instance knowing
#9 Use Getters and Setters
class Tally
{
public $total = 0;

public function add($amount)
{
$this->total += $amount
}
}

$tally = new Tally();

total can be changed without
this instance knowing

$tally->add(1);
// some other code ...
$tally->total = -1
// some other code ...
$tally->add(1);
echo $tally->total . PHP_EOL;

Causes unexpected results
#9 Use Getters and Setters
class Tally

total cannot be “reset”

{
private $total = 0;
public function add($amount)
{
$this->total += $amount;
}
public function getTotal()
{
return $this->total;
}
}
$tally = new Tally();
$tally->add(1);
$tally->add(1);
echo $tally->getTotal() . PHP_EOL;

No unexpected results
#9 Use Getters and Setters
Warning!!!
Excessive setters and getters can be just as
bad as public properties
#9 Use Getters and Setters
Key Benefits
● Injector operations
● Encapsulation of transformations
● Encourages Open/Closed principle
Recap
1.
2.
3.
4.
5.
6.
7.
8.
9.

One level of indentation per method
Don’t use the else keyword
Wrap primitives that have behavior
Use first class collections
One object operator per line
Do not abbreviate
Keep classes small
Limit instance variables in a class
Use Getters and setters
Object Calisthenics
http://www.bennadel.com/resources/uploads/2012/ObjectCalisthenics.pdf

@chadicus78
@hrphpmeetup

Give us feedback at
http://de12bcon.herokuapp.com/survey

Weitere ähnliche Inhalte

Was ist angesagt?

Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsRoss Tuck
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm OldRoss Tuck
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...Rafael Dohms
 
Gta v savegame
Gta v savegameGta v savegame
Gta v savegamehozayfa999
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolveXSolve
 
Xlab #1: Advantages of functional programming in Java 8
Xlab #1: Advantages of functional programming in Java 8Xlab #1: Advantages of functional programming in Java 8
Xlab #1: Advantages of functional programming in Java 8XSolve
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needKacper Gunia
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Colin O'Dell
 
SfCon: Test Driven Development
SfCon: Test Driven DevelopmentSfCon: Test Driven Development
SfCon: Test Driven DevelopmentAugusto Pascutti
 
PHP Language Trivia
PHP Language TriviaPHP Language Trivia
PHP Language TriviaNikita Popov
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksNate Abele
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixturesBill Chang
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
Revisiting SOLID Principles
Revisiting  SOLID Principles Revisiting  SOLID Principles
Revisiting SOLID Principles Anis Ahmad
 
Writing Sensible Code
Writing Sensible CodeWriting Sensible Code
Writing Sensible CodeAnis Ahmad
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHPTaras Kalapun
 

Was ist angesagt? (20)

Models and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and HobgoblinsModels and Service Layers, Hemoglobin and Hobgoblins
Models and Service Layers, Hemoglobin and Hobgoblins
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
Things I Believe Now That I'm Old
Things I Believe Now That I'm OldThings I Believe Now That I'm Old
Things I Believe Now That I'm Old
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
 
Gta v savegame
Gta v savegameGta v savegame
Gta v savegame
 
Shell.php
Shell.phpShell.php
Shell.php
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
Xlab #1: Advantages of functional programming in Java 8
Xlab #1: Advantages of functional programming in Java 8Xlab #1: Advantages of functional programming in Java 8
Xlab #1: Advantages of functional programming in Java 8
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016Hacking Your Way To Better Security - Dutch PHP Conference 2016
Hacking Your Way To Better Security - Dutch PHP Conference 2016
 
SfCon: Test Driven Development
SfCon: Test Driven DevelopmentSfCon: Test Driven Development
SfCon: Test Driven Development
 
PHP Language Trivia
PHP Language TriviaPHP Language Trivia
PHP Language Trivia
 
PHP and MySQL
PHP and MySQLPHP and MySQL
PHP and MySQL
 
Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Presentation1
Presentation1Presentation1
Presentation1
 
Revisiting SOLID Principles
Revisiting  SOLID Principles Revisiting  SOLID Principles
Revisiting SOLID Principles
 
Writing Sensible Code
Writing Sensible CodeWriting Sensible Code
Writing Sensible Code
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
 

Ähnlich wie Object Calisthenics Adapted for PHP

Your code sucks, let's fix it - PHP Master Series 2012
Your code sucks, let's fix it - PHP Master Series 2012Your code sucks, let's fix it - PHP Master Series 2012
Your code sucks, let's fix it - PHP Master Series 2012Rafael Dohms
 
Your code sucks, let's fix it
Your code sucks, let's fix itYour code sucks, let's fix it
Your code sucks, let's fix itRafael Dohms
 
Your code sucks, let's fix it (CakeFest2012)
Your code sucks, let's fix it (CakeFest2012)Your code sucks, let's fix it (CakeFest2012)
Your code sucks, let's fix it (CakeFest2012)Rafael Dohms
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにYuya Takeyama
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in actionJace Ju
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developersStoyan Stefanov
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsSam Hennessy
 
Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Nikita Popov
 
Coding for Scale and Sanity
Coding for Scale and SanityCoding for Scale and Sanity
Coding for Scale and SanityJimKellerES
 
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoエラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoShohei Okada
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console componentHugo Hamon
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersIan Barber
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPWildan Maulana
 
Javascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introductionJavascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introductionIban Martinez
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownpartsBastian Feder
 

Ähnlich wie Object Calisthenics Adapted for PHP (20)

Your code sucks, let's fix it - PHP Master Series 2012
Your code sucks, let's fix it - PHP Master Series 2012Your code sucks, let's fix it - PHP Master Series 2012
Your code sucks, let's fix it - PHP Master Series 2012
 
Your code sucks, let's fix it
Your code sucks, let's fix itYour code sucks, let's fix it
Your code sucks, let's fix it
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Your code sucks, let's fix it (CakeFest2012)
Your code sucks, let's fix it (CakeFest2012)Your code sucks, let's fix it (CakeFest2012)
Your code sucks, let's fix it (CakeFest2012)
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
JavaScript for PHP developers
JavaScript for PHP developersJavaScript for PHP developers
JavaScript for PHP developers
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Taming Command Bus
Taming Command BusTaming Command Bus
Taming Command Bus
 
Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?Typed Properties and more: What's coming in PHP 7.4?
Typed Properties and more: What's coming in PHP 7.4?
 
Value objects
Value objectsValue objects
Value objects
 
Coding for Scale and Sanity
Coding for Scale and SanityCoding for Scale and Sanity
Coding for Scale and Sanity
 
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyoエラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
エラー時にログに出力する情報と画面に表示する情報を分ける #LaravelTokyo
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
 
Teaching Your Machine To Find Fraudsters
Teaching Your Machine To Find FraudstersTeaching Your Machine To Find Fraudsters
Teaching Your Machine To Find Fraudsters
 
Smelling your code
Smelling your codeSmelling your code
Smelling your code
 
Bacbkone js
Bacbkone jsBacbkone js
Bacbkone js
 
Object Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOPObject Oriented Programming with PHP 5 - More OOP
Object Oriented Programming with PHP 5 - More OOP
 
Javascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introductionJavascript & jQuery: A pragmatic introduction
Javascript & jQuery: A pragmatic introduction
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 

Kürzlich hochgeladen

Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Igalia
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGSujit Pal
 

Kürzlich hochgeladen (20)

Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
Raspberry Pi 5: Challenges and Solutions in Bringing up an OpenGL/Vulkan Driv...
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Google AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAGGoogle AI Hackathon: LLM based Evaluator for RAG
Google AI Hackathon: LLM based Evaluator for RAG
 

Object Calisthenics Adapted for PHP

  • 2. A little about me ● ● ● ● ● ● ● Bedford, VA Radford University 9+ Years PHP 8+ Years @ DE Hampton Roads PHP Comics Every Hulk Issue
  • 3. Object Calisthenics ● ● ● ● ● ● First introduced by Jeff Bay Based on Java Development Guidelines Not Rules Difficulty varies Write Better Code Adapted for PHP
  • 4. Object Calisthenics #1 “Only one level of indentation per method”
  • 5. #1 Only one level of indentation public function validate(array $products) { $requiredFields = ['price', 'name', 'description']; $valid = true; foreach ($products as $rawProduct) { $fields = array_keys($rawProduct); foreach ($requiredFields as $requiredField) { if (!in_array($requiredField, $fields)) { $valid = false; } } } return $valid; }
  • 6. #1 Only one level of indentation public function validate(array $products) { $requiredFields = ['price', 'name', 'description']; $valid = true; 0 foreach ($products as $rawProduct) { 1 $fields = array_keys($rawProduct); foreach ($requiredFields as $requiredField) { 2 if (!in_array($requiredField, $fields)) { 3 $valid = false; } } } return $valid; }
  • 7. #1 Only one level of indentation public function validate(array $products) { $requiredFields = ['price', 'name', 'description']; $valid = true; foreach ($products as $rawProduct) { $valid = $valid && $this->validateSingle($rawProduct, $requiredFields); } return $valid; } public function validateSingle(array $product, array $requiredFields) { $fields = array_keys($product); return count(array_diff($requiredFields, $fields)) == 0; }
  • 8. #1 Only one level of indentation Key Benefits ● Encourages Single Responsibility ● Increase Re-use
  • 9. Object Calisthenics #2 “Do not use the ‘else’ keyword”
  • 10. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } elseif (is_string($exception)) { if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } } else { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } }
  • 11. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } elseif (is_string($exception)) { if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } } else { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } }
  • 12. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } elseif (is_string($exception)) { if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } } else { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } }
  • 13. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { return early throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } elseif (is_string($exception)) { if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } } else { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } }
  • 14. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } if (is_string($exception)) { if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } } else { throw new InvalidArgumentException('$exception was not a string, Exception or null'); }
  • 15. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); reverse condition } if (is_string($exception)) { if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } } else { throw new InvalidArgumentException('$exception was not a string, Exception or null'); }
  • 16. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } if (!is_string($exception)) { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } }
  • 17. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } if (!is_string($exception)) { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } if ($exceptionArgs === null) { throw new Exception($exception); } else { if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); } } return early
  • 18. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } if (!is_string($exception)) { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } if ($exceptionArgs === null) { throw new Exception($exception); } if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); }
  • 19. #2 Do not use the ‘else’ keyword public function ensure($valueToEnsure, $valueToCheck, $exception = null, array $exceptionArgs = null) { if ($valueToEnsure === $valueToCheck) { return $valueToCheck; } if ($exception === null) { throw new Exception("'{$valueToEnsure}' did not equal '{$valueToCheck}'"); } if (!is_string($exception)) { throw new InvalidArgumentException('$exception was not a string, Exception or null'); } if ($exceptionArgs === null) { throw new Exception($exception); } if (array_key_exists($exception, self::$_exceptionAliases)) { $exception = self::$_exceptionAliases[$exception]; } $reflectionClass = new ReflectionClass($exception); throw $reflectionClass->newInstanceArgs($exceptionArgs); }
  • 20. #2 Do not use the ‘else’ keyword Key Benefits ● Helps avoid code duplication ● Easier to read (single path) ● Reduces cyclomatic complexity
  • 21. Object Calisthenics #3 “Wrap all primitives and Strings” *If there is behavior
  • 22. #3 Wrap primitives and Strings class Item { final public static function find($id) { if (!is_string($id) || trim($id) == '') throw new InvalidArgumentException('$id must be a non-empty string'); // do find ... } final public static function create($id, array $data) { if (!is_string($id) || trim($id) == '') throw new InvalidArgumentException('$id must be a non-empty string'); // do create ... } }
  • 23. #3 Wrap primitives and Strings class Item { final public static function find($id) { validation with id if (!is_string($id) || trim($id) == '') throw new InvalidArgumentException('$id must be a non-empty string'); // do find ... } final public static function create($id, array $data) validation with id { if (!is_string($id) || trim($id) == '') throw new InvalidArgumentException('$id must be a non-empty string'); // do create ... } }
  • 24. #3 Wrap primitives and Strings class Id { private $value; final public function __construct($value) { if (!is_string($value) || trim($value) == '') throw new InvalidArgumentException('$value must be a non-empty string'); $this->value = $value; } final public function getValue() { return $this->value; } }
  • 25. #3 Wrap primitives and Strings class Id { private $value; final public function __construct($value) validation encapsulated in constructor { if (!is_string($value) || trim($value) == '') throw new InvalidArgumentException('$value must be a non-empty string'); $this->value = $value; } final public function getValue() { return $this->value; } }
  • 26. #3 Wrap primitives and Strings class Item { final public static function find(Id $id) { // do find ... } final public static function create(Id $id, array $data) { // do create ... } }
  • 27. #3 Wrap primitives and Strings class Item { final public static function find(Id $id) { // do find ... } final public static function create(Id $id, array $data) { // do create ... } } $id now guaranteed to be valid.
  • 28. #3 Wrap primitives and Strings Warning!!! Using large amounts of objects will increase the memory footprint of PHP.
  • 29. #3 Wrap primitives and Strings Key Benefits ● Type Hinting ● Encapsulation of operations
  • 30. Object Calisthenics #4 “Use first class collections”
  • 31. #4 Use first class collections A class that contains a collection should contain no other instance variables.
  • 32. #4 Use first class collections class Items implements Iterator { private $items = []; final public function add(Item $item) { // do add ... } final public function filter(array $filters) { // do filter ... } final public function merge(Items $items) { // do merge ... } }
  • 33. #4 Use first class collections Key Benefits ● Implements collection operations ● Uses SPL interfaces ● Easier to merge collections and not worry about member behavior in them
  • 34. Object Calisthenics #5 “One object operator per line”
  • 35. #5 One object operator per line $this->manager->getConfig()->getSegment()->setName('foo');
  • 36. #5 One object operator per line Properties are harder to mock $this->manager->getConfig()->getSegment()->setName('foo');
  • 37. #5 One object operator per line Properties are harder to mock $this->manager->getConfig()->getSegment()->setName('foo'); Previous call could return null
  • 38. #5 One object operator per line Properties are harder to mock May indicate feature envy $this->manager->getConfig()->getSegment()->setName('foo'); Previous call could return null
  • 39. #5 One object operator per line Key Benefits ● Readability ● Easier Testing ● Easier to Debug
  • 40. Object Calisthenics #6 “Do not abbreviate”
  • 41. #6 Do not abbreviate public function getPage() { ... } public function startProcess() { ... } $smp->process("index");
  • 42. #6 Do not abbreviate get what page from where? public function getPage() { ... } public function startProcess() { ... } $smp->process("index");
  • 43. #6 Do not abbreviate get from where? public function getPage() { ... } public function startProcess() { ... } $smp->process("index"); ???
  • 44. #6 Do not abbreviate get what page from where? public function getPage() { ... } Use clearer names: renderHomePage() downloadHomePage() public function startProcess() { ... } $smp->process("index"); ???
  • 45. #6 Do not abbreviate get what page from where? public function getPage() { ... } Use clearer names: renderHomePage() downloadHomePage() public function startProcess() { ... } $smp->process("index"); ??? Use a thesaurus: fork, create, begin, open
  • 46. #6 Do not abbreviate get what page from where? public function getPage() { ... } Use clearer names: renderHomePage() downloadHomePage() public function startProcess() { ... } $smp->process("index"); ??? Use a thesaurus: fork, create, begin, open Easy understanding, complete scope: $siteMapProcessor
  • 47. #6 Do not abbreviate Key Benefits ● Clearer communication and maintainability ● Indicates underlying problems
  • 48. Object Calisthenics #7 “Keep classes small”
  • 49. #7 Keep classes small 200 lines per class (including docblocks) 10 methods per class 15 classes per namespace (folder)
  • 50. #7 Keep classes small Key Benefits ● Single Responsibility ● Objective and clear methods ● Slimmer namespaces
  • 51. Object Calisthenics #8 “Limit the number of instance variables in a class”
  • 52. #8 Limit instance variables in a class class Client { private $_adapter; private $_cache; private $_logger; // ... } Limit: 2 - 5
  • 53. #8 Limit instance variables in a class Key Benefits ● Shorter dependency list ● Easier Mocking for unit tests
  • 54. Object Calisthenics #9 “Use getters/setters”
  • 55. #9 Use Getters and Setters class Tally { public $total = 0; public function add($amount) { $this->total += $amount; } } $tally = new Tally(); $tally->add(1); // some other code ... $tally->total = -1; // some other code ... $tally->add(1); echo $tally->total . PHP_EOL;
  • 56. #9 Use Getters and Setters class Tally { public $total = 0; public function add($amount) { $this->total += $amount } } $tally = new Tally(); $tally->add(1); // some other code ... $tally->total = -1 // some other code ... $tally->add(1); echo $tally->total . PHP_EOL; total can be changed without this instance knowing
  • 57. #9 Use Getters and Setters class Tally { public $total = 0; public function add($amount) { $this->total += $amount } } $tally = new Tally(); total can be changed without this instance knowing $tally->add(1); // some other code ... $tally->total = -1 // some other code ... $tally->add(1); echo $tally->total . PHP_EOL; Causes unexpected results
  • 58. #9 Use Getters and Setters class Tally total cannot be “reset” { private $total = 0; public function add($amount) { $this->total += $amount; } public function getTotal() { return $this->total; } } $tally = new Tally(); $tally->add(1); $tally->add(1); echo $tally->getTotal() . PHP_EOL; No unexpected results
  • 59. #9 Use Getters and Setters Warning!!! Excessive setters and getters can be just as bad as public properties
  • 60. #9 Use Getters and Setters Key Benefits ● Injector operations ● Encapsulation of transformations ● Encourages Open/Closed principle
  • 61. Recap 1. 2. 3. 4. 5. 6. 7. 8. 9. One level of indentation per method Don’t use the else keyword Wrap primitives that have behavior Use first class collections One object operator per line Do not abbreviate Keep classes small Limit instance variables in a class Use Getters and setters