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
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
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
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
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
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