![Page 1: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/1.jpg)
PHP 4 ADULTSOBJECT CALISTHENICS AND CLEAN CODE
![Page 2: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/2.jpg)
GUILHERMEBLANCO
GUILHERMEBLANCO
Guilherme Blanco
![Page 3: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/3.jpg)
MOTIVATION
▸ Readability
▸ Maintainability
▸ Reusability
▸ Testability
![Page 4: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/4.jpg)
SUMMING UP…
![Page 5: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/5.jpg)
![Page 6: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/6.jpg)
CLEAN CODE
![Page 7: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/7.jpg)
S T U P I D
![Page 8: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/8.jpg)
SINGLETON TIGHT COUPLING UNTESTABILITY PREMATURE OPTIMIZATION INDESCRIPTIVE NAMING DUPLICATION
![Page 9: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/9.jpg)
S O L I D
![Page 10: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/10.jpg)
SINGLE RESPONSIBILITY OPEN/CLOSED PRINCIPLE LISKOV SUBSTITUTION PRINCIPLE INTERFACE SEGREGATION DEPENDENCY INVERSION
![Page 11: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/11.jpg)
LISKOV SUBSTITUTION PRINCIPLE
![Page 12: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/12.jpg)
interface Bird { public function setLocation($longitude, $latitude);
public function setHeight($height);
public function draw(); }
![Page 13: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/13.jpg)
class Penguin implements Bird { public function setHeight($height) { // Do nothing }
}
![Page 14: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/14.jpg)
interface Bird { public function setLocation($longitude, $latitude);
public function draw();}
interface FlightfulBird extends Bird { public function setHeight($height);
}
![Page 15: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/15.jpg)
DEPENDENCY INVERSION PRINCIPLE
![Page 16: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/16.jpg)
namespace Dating\UserBundle\Entity { class User { /** @var \Dating\UserBundle\Entity\Image */ protected $avatar; } }
namespace Dating\MediaBundle\Entity { class Image { /** @var \Dating\UserBundle\Entity\User */ protected $owner; } }
![Page 17: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/17.jpg)
namespace Dating\UserBundle\Entity { class User { /** @var AvatarInterface */ protected $avatar; }
interface AvatarInterface { // ... }}
namespace Dating\MediaBundle\Entity { use Dating\UserBundle\Entity\AvatarInterface;
class Image implements AvatarInterface { /** @var \Dating\UserBundle\Entity\User */ protected $owner; } }
![Page 18: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/18.jpg)
OBJECT CALISTHENICS
![Page 19: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/19.jpg)
RULE #1ONLY ONE INDENTATION LEVEL PER METHOD
![Page 20: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/20.jpg)
public function validateForm($filters='', $validators='', $options='') { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if ($input->hasInvalid() || $input->hasMissing()) { foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, "javascript:history.back();" ); } else { throw new Tss_FormException( "{$message}", 3, "javascript:history.back();" ); } } } }
return $input;}
![Page 21: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/21.jpg)
12
34
public function validateForm($filters='', $validators='', $options='') { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if ($input->hasInvalid() || $input->hasMissing()) { foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, "javascript:history.back();" ); } else { throw new Tss_FormException( "{$message}", 3, "javascript:history.back();" ); } } } }
return $input;}
Class prototype
![Page 22: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/22.jpg)
EARLY RETURNS
![Page 23: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/23.jpg)
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, "javascript:history.back();" ); } else { throw new Tss_FormException( "{$message}", 3, "javascript:history.back();" ); } } }
return $input;}
![Page 24: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/24.jpg)
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, "javascript:history.back();" ); } else { throw new Tss_FormException( "{$message}", 3, "javascript:history.back();" ); } } }
return $input;}
![Page 25: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/25.jpg)
12
3
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { if (strpos($message, "empty")) { throw new Tss_FormException( "The field {$field} cannot be empty!", 3, "javascript:history.back();" ); } else { throw new Tss_FormException( "{$message}", 3, "javascript:history.back();" ); } } }
return $input;}
![Page 26: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/26.jpg)
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : $message;
throw new Tss_FormException( $errorMessage, 3, "javascript:history.back();" ); } }
return $input;}
![Page 27: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/27.jpg)
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : $message;
throw new Tss_FormException( $errorMessage, 3, "javascript:history.back();" ); } }
return $input;}
![Page 28: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/28.jpg)
12
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { foreach ($messageList as $message) { $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : $message;
throw new Tss_FormException( $errorMessage, 3, "javascript:history.back();" ); } }
return $input;}
![Page 29: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/29.jpg)
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { $message = array_shift($messageList); $jsAction = "javascript:history.back();"; $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : $message;
throw new Tss_FormException($errorMessage, 3, $jsAction); }
return $input;}
![Page 30: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/30.jpg)
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST;
$input = new Zend_Filter_Input($filters, $validators, $data, $options); $input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { $message = array_shift($messageList); $jsAction = "javascript:history.back();"; $errorMessage = (strpos($message, "empty") === false) ? "The field {$field} cannot be empty!" : $message;
throw new Tss_FormException($errorMessage, 3, $jsAction); }
return $input;}
Logical groups
Variable interpolation
![Page 31: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/31.jpg)
public function validateForm($filters=array(), $validators=array(), $options=array()) { $data = $_POST; $input = new Zend_Filter_Input($filters, $validators, $data, $options);
$input->setDefaultEscapeFilter(new Zend_Filter_StringTrim());
if (! ($input->hasInvalid() || $input->hasMissing())) { return $input; }
foreach ($input->getMessages() as $field => $messageList) { $message = array_shift($messageList); $jsAction = "javascript:history.back();"; $errorMessage = (strpos($message, "empty") === false) ? sprintf("The field %s cannot be empty!", $field) : $message;
throw new Tss_FormException($errorMessage, 3, $jsAction); }
return $input;}
![Page 32: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/32.jpg)
BENEFITS
▸ Single Responsibility Principle ("S" in SOLID)
▸ Reusability
![Page 33: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/33.jpg)
RULE #2NO "ELSE" KEYWORD
![Page 34: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/34.jpg)
public function createPost($request) { $entity = new Post(); $form = new MyForm($entity); $form->bind($request); if ($form->isValid()){ $repository = $this->getRepository('MyBundle:Post'); if (!$repository->exists($entity)) { $repository->save($entity); return $this->redirect('create_ok'); } else { $error = "Post Title already exists"; return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields"; return array('form' => $form, 'error' => $error); } }
![Page 35: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/35.jpg)
public function createPost($request) { $entity = new Post(); $form = new MyForm($entity); $form->bind($request); if ($form->isValid()){ $repository = $this->getRepository('MyBundle:Post'); if (!$repository->exists($entity)) { $repository->save($entity); return $this->redirect('create_ok'); } else { $error = "Post Title already exists"; return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields"; return array('form' => $form, 'error' => $error); } }
Type-casting
Coding standards
Separate into logical groups.
Consider as paragraphs!
![Page 36: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/36.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if ($form->isValid()) { if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); } }
![Page 37: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/37.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if ($form->isValid()) { if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); } }
![Page 38: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/38.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if ($form->isValid()) { if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); } }
![Page 39: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/39.jpg)
UMLNORMAL VS. ALTERNATIVE FLOWS
![Page 40: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/40.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if ($form->isValid()) { if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); } }
![Page 41: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/41.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if ($form->isValid()) { if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); } }
![Page 42: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/42.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if ($form->isValid()) { if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } } else { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); } }
![Page 43: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/43.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if (! $form->isValid()) { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); }
if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } }
![Page 44: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/44.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if (! $form->isValid()) { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); }
if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } }
![Page 45: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/45.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if (! $form->isValid()) { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); }
if (! $repository->exists($entity)) { $repository->save($entity);
return $this->redirect('create_ok'); } else { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); } }
![Page 46: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/46.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if (! $form->isValid()) { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); }
if ($repository->exists($entity)) { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); }
$repository->save($entity);
return $this->redirect('create_ok');}
![Page 47: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/47.jpg)
public function createPost(Request $request) { $repository = $this->getRepository(‘MyBundle:Post'); $entity = new Post(); $form = new MyForm($entity);
$form->bind($request);
if (! $form->isValid()) { $error = "Invalid fields";
return array('form' => $form, 'error' => $error); }
if ($repository->exists($entity)) { $error = "Post Title already exists";
return array('form' => $form, 'error' => $error); }
$repository->save($entity);
return $this->redirect('create_ok');}
![Page 48: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/48.jpg)
BENEFITS
▸ Prevents code duplication
▸ Increases legibility
▸ Reduce cyclomatic complexity
![Page 49: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/49.jpg)
RULE #3ENCAPSULATE ALL PRIMITIVE TYPES AND STRINGS
![Page 50: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/50.jpg)
RULE #3ENCAPSULATE ALL PRIMITIVE TYPES AND STRINGS
IF THEY HAVE BEHAVIOR
![Page 51: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/51.jpg)
BUT… WHY?
![Page 52: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/52.jpg)
EXCESSIVE USAGE OF OBJECTS IN PHP (IF PHP <7!) DRASTICALLY INCREASES MEMORY FOOTPRINT!
Guilherme Blanco
![Page 53: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/53.jpg)
class Item { final public static function find($id) { if (is_string($id) && trim($id) != '') { // do find ... }
throw new \InvalidArgumentException('$id must be a non-empty string'); }
final public static function create($id, array $data) { if ( ! is_string($id)) { throw new \InvalidArgumentException('$id must be a string'); }
if (empty(trim($id))) { throw new \InvalidArgumentException('$id must be a non-empty string'); }
// do create ... }}
![Page 54: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/54.jpg)
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 ... }}
![Page 55: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/55.jpg)
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 ... }}
![Page 56: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/56.jpg)
final class Id { /** @var string */ public $value;
public function __construct($value) { if (! is_string($id) || trim($id) === '') { $message = sprintf('%s must be a non-empty string', $value);
throw new \InvalidArgumentException($message); }
$this->value = $value; }
public function getValue() { return $this->value; }}
![Page 57: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/57.jpg)
class Item { final public static function find(Id $id) { // do find ... }
final public static function create(Id $id, array $data) { // do create ... }}
![Page 58: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/58.jpg)
BENEFITS
▸ Type hinting
▸ Encapsulation
▸ Prevents code duplication
![Page 59: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/59.jpg)
RULE #4ONE OBJECT OPERATOR (->) PER LINE
![Page 60: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/60.jpg)
$this->manager->getConfig()->getSegment()->setName("foo");
Properties are hard to mock What if previous call returned NULL?
![Page 61: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/61.jpg)
JUST USE A NULL OBJECT!
Someone watching this talk, one day
![Page 62: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/62.jpg)
final class NullObject { public function __get($property) { return new self; }
public function __set($property, $value) { return new self; }
public function __call($method, array $arguments) { return new self; }
public function __callStatic($method, array $arguments) { return new self; }
public function__toString() { return 'null'; } }
![Page 63: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/63.jpg)
WHY IS IT BAD?
▸ Hide encapsulation problem
▸ Hard to debug and handle exceptions
▸ Codebase must be structured to use NullObject
▸ Hard to read and understand
![Page 64: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/64.jpg)
EXCEPTION TO RULEFLUENT INTERFACE UNDER SAME METHOD
![Page 65: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/65.jpg)
$filterChain ->addFilter(new Zend_Filter_Alpha()) ->addFilter(new Zend_Filter_StringToLower());
![Page 66: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/66.jpg)
BENEFITS
▸ Law of Demeter
▸ Readability
▸ Increases testability (easier to mock)
▸ Simplifies debugging
![Page 67: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/67.jpg)
RULE #5DO NOT ABBREVIATE
![Page 68: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/68.jpg)
THERE ARE 2 HARD PROBLEMS IN COMPUTER SCIENCE: CACHE INVALIDATION, NAMING THINGS AND OFF BY 1 ERRORS.
Tim Bray (mentioning Phil Karlton)
![Page 69: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/69.jpg)
WHY DO YOU ABBREVIATE?
![Page 70: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/70.jpg)
CODE DUPLICATION PROBLEM!WRITE SAME NAME REPEATEDLY
![Page 71: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/71.jpg)
MULTIPLE RESPONSIBILITY PROBLEM!
LONG NAMES
![Page 72: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/72.jpg)
public function getPage($data) { ... }
"Get" from where?
public function startProcess() { ... }
$trx->process('site.login');
How?
WTF is that?
renderHomePage
forkIntoChildProcess
extendedTranslator
![Page 73: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/73.jpg)
BENEFITS
▸ Readability
▸ Better exposing method’s intent
▸ Improved maintainability
▸ Good indicator of code duplication and encapsulation
![Page 74: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/74.jpg)
RULE #6KEEP YOUR CLASSES SMALL
![Page 75: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/75.jpg)
OBJECTIVE
▸ Maximum 200 lines per class(including docblock/documentation)
▸ 10 methods per class
▸ Up to 20 lines per method
▸ 15 classes/interfaces/traits per namespace
![Page 76: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/76.jpg)
BENEFITS
▸ Single Responsibility Principle
▸ Clear and objective methods
▸ Better code segregation
▸ Cleaner namespaces
![Page 77: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/77.jpg)
RULE #7LIMIT CLASS INSTANCE VARIABLES IN A CLASS (BETWEEN 2 TO 5)
![Page 78: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/78.jpg)
class MyRegistrationService { protected $userService; protected $passwordService;
protected $logger;
protected $translator;
protected $entityManager;
protected $imageCropper;
// ... }
Database interactions should be on UserService
Rely on an Event system and move this to a listener
Cross-cutting concerns. Should be auto-injected by your DI through an interface hint
![Page 79: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/79.jpg)
class MyRegistrationService implements LoggerAwareInterface, TranslatorAwareInterface{ use LoggerAwareTrait; use TranslatorAwareTrait;
protected $userService; protected $passwordService;
protected $eventDispatcher;
// ... }
![Page 80: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/80.jpg)
BENEFITS
▸ Single Responsibility Principle
▸ Loose coupling
▸ Better encapsulation
▸ Testability
![Page 81: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/81.jpg)
RULE #8USE FIRST CLASS COLLECTIONS
![Page 82: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/82.jpg)
OR IN OTHER TERMS…
![Page 83: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/83.jpg)
ANY CLASS THAT CONTAINS AN ARRAY MUST NOT HAVE ANY OTHER PROPERTY.
Guilherme Blanco
TEXT
![Page 84: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/84.jpg)
class User { private $name; // ... private $albumList = array();
public function getPublicAlbumList() { $filteredAlbumList = array();
foreach ($this->albumList as $album) { if ($album->getPrivacy() === AlbumPrivacy::PUBLIC) { $filteredAlbumList[] = $album; } } return $filteredAlbumList; }
// ... }
$publicAlbumList = $user->getPublicAlbumList();
![Page 85: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/85.jpg)
class AlbumList extends Collection{ public function getPublic() { $filteredAlbumList = array();
foreach ($this->value as $album) { if ($album->getPrivacy() === AlbumPrivacy::PUBLIC) { $filteredAlbumList[] = $album; } } return $filteredAlbumList; } }
class User{ private $name; private $albumList = new AlbumList(); // ... }
$publicAlbumList = $user->getAlbumList()->getPublic();
![Page 86: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/86.jpg)
class AlbumList extends Collection{ public function getPublic() { return new ArrayCollection( array_filter( $this->value, function (Album $album) { return $album->isPublic(); } ) ); } }
class User{ private $name; private $albumList = new AlbumList(); // ... }
$publicAlbumList = $user->getAlbumList()->getPublic();
![Page 87: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/87.jpg)
BENEFITS
▸ Single Responsibility Principle
▸ Collection operations implemented inside of Collection
▸ Usage of SPL classes
▸ Easy to group collections without concerns over their members’ behavior
▸ Filtering, ordering, mapping, combining are good example methods
![Page 88: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/88.jpg)
RULE #9USE GETTERS AND SETTERS
![Page 89: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/89.jpg)
class BankAccount { public $balance = 0;
public function deposit($amount) { $this->balance += $amount; }
public function withdraw($amount) { $this->balance -= $amount; }}
// Example: $account = new BankAccount(); $account->deposit(100.00); // ... $account->balance = 0; // ... $account->withdraw(10.00);
Balance can be modified without class being notified, leading to unexpected errors.
![Page 90: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/90.jpg)
BENEFITS
▸ Operations injection
▸ Transformations encapsulation
▸ Promotes Open/Closed Principle ("O" in SOLID)
![Page 91: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/91.jpg)
QUESTIONS?
![Page 92: PHP for Adults: Clean Code and Object Calisthenics](https://reader030.vdocuments.mx/reader030/viewer/2022021500/58efcada1a28ab80688b45d7/html5/thumbnails/92.jpg)
THANKS! =) GUILHERMEBLANCO
GUILHERMEBLANCO