SlideShare a Scribd company logo
PHP 4 ADULTS
OBJECT CALISTHENICS AND CLEAN CODE
GUILHERMEBLANCO
GUILHERMEBLANCO
Guilherme Blanco
MOTIVATION
▸ Readability
▸ Maintainability
▸ Reusability
▸ Testability
SUMMING UP…
CLEAN CODE
S T U P I D
SINGLETON
TIGHT COUPLING
UNTESTABILITY
PREMATURE OPTIMIZATION
INDESCRIPTIVE NAMING
DUPLICATION
S O L I D
SINGLE RESPONSIBILITY
OPEN/CLOSED PRINCIPLE
LISKOV SUBSTITUTION PRINCIPLE
INTERFACE SEGREGATION
DEPENDENCY INVERSION
LISKOV SUBSTITUTION
PRINCIPLE
interface Bird
{
public function setLocation($longitude, $latitude);
public function setHeight($height);
public function draw();
}
class Penguin implements Bird
{
public function setHeight($height)
{
// Do nothing
}
}
interface Bird
{
public function setLocation($longitude, $latitude);
public function draw();
}
interface FlightfulBird extends Bird 

{ 

public function setHeight($height);
}
DEPENDENCY
INVERSION PRINCIPLE
namespace DatingUserBundleEntity
{
class User
{
/** @var DatingUserBundleEntityImage */
protected $avatar;
}
}
namespace DatingMediaBundleEntity
{
class Image
{
/** @var DatingUserBundleEntityUser */
protected $owner;
} 

}
namespace DatingUserBundleEntity
{
class User
{
/** @var AvatarInterface */
protected $avatar;
}
interface AvatarInterface
{
// ...
}
}
namespace DatingMediaBundleEntity
{
use DatingUserBundleEntityAvatarInterface;
class Image implements AvatarInterface
{
/** @var DatingUserBundleEntityUser */
protected $owner;
} 

}
OBJECT
CALISTHENICS
RULE #1
ONLY ONE INDENTATION LEVEL PER
METHOD
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;
}
1
2
3
4
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
EARLY RETURNS
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;
}
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;
}
1
2
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;
}
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;
}
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;
}
1
2
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;
}
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;
}
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
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;
}
BENEFITS
▸ Single Responsibility Principle ("S" in SOLID)
▸ Reusability
RULE #2
NO "ELSE" KEYWORD
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);
}
}
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!
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);
}
}
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);
}
}
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);
}
}
UML
NORMAL VS. ALTERNATIVE FLOWS
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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);
}
}
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');
}
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');
}
BENEFITS
▸ Prevents code duplication
▸ Increases legibility
▸ Reduce cyclomatic complexity
RULE #3
ENCAPSULATE ALL PRIMITIVE TYPES
AND STRINGS
RULE #3
ENCAPSULATE ALL PRIMITIVE TYPES
AND STRINGS
IF THEY HAVE BEHAVIOR
BUT… WHY?
EXCESSIVE USAGE OF OBJECTS IN
PHP (IF PHP <7!) DRASTICALLY
INCREASES MEMORY FOOTPRINT!
Guilherme Blanco
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 ...
}
}
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 ...
}
}
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 ...
}
}
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;
}
}
class Item
{
final public static function find(Id $id)
{
// do find ...
}
final public static function create(Id $id, array $data)
{
// do create ...
}
}
BENEFITS
▸ Type hinting
▸ Encapsulation
▸ Prevents code duplication
RULE #4
ONE OBJECT OPERATOR (->) PER LINE
$this->manager->getConfig()->getSegment()->setName("foo");
Properties are hard to mock What if previous call returned NULL?
JUST USE A NULL OBJECT!
Someone watching this talk, one day
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';
}
}
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
EXCEPTION TO RULE
FLUENT INTERFACE UNDER SAME
METHOD
$filterChain 

->addFilter(new Zend_Filter_Alpha())
->addFilter(new Zend_Filter_StringToLower())
;
BENEFITS
▸ Law of Demeter
▸ Readability
▸ Increases testability (easier to mock)
▸ Simplifies debugging
RULE #5
DO NOT ABBREVIATE
THERE ARE 2 HARD PROBLEMS IN
COMPUTER SCIENCE: CACHE
INVALIDATION, NAMING THINGS AND
OFF BY 1 ERRORS.
Tim Bray (mentioning Phil Karlton)
WHY DO YOU
ABBREVIATE?
CODE DUPLICATION PROBLEM!
WRITE SAME NAME REPEATEDLY
MULTIPLE RESPONSIBILITY
PROBLEM!
LONG NAMES
public function getPage($data) { ... }
"Get" from where?
public function startProcess() { ... }
$trx->process('site.login');
How?
WTF is that?
renderHomePage
forkIntoChildProcess
extendedTranslator
BENEFITS
▸ Readability
▸ Better exposing method’s intent
▸ Improved maintainability
▸ Good indicator of code duplication and encapsulation
RULE #6
KEEP YOUR CLASSES SMALL
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
BENEFITS
▸ Single Responsibility Principle
▸ Clear and objective methods
▸ Better code segregation
▸ Cleaner namespaces
RULE #7
LIMIT CLASS INSTANCE VARIABLES IN A
CLASS (BETWEEN 2 TO 5)
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
class MyRegistrationService
implements LoggerAwareInterface, TranslatorAwareInterface
{
use LoggerAwareTrait;
use TranslatorAwareTrait;
protected $userService;
protected $passwordService;
protected $eventDispatcher;
// ...
}
BENEFITS
▸ Single Responsibility Principle
▸ Loose coupling
▸ Better encapsulation
▸ Testability
RULE #8
USE FIRST CLASS COLLECTIONS
OR IN OTHER
TERMS…
ANY CLASS THAT CONTAINS AN
ARRAY MUST NOT HAVE ANY
OTHER PROPERTY.
Guilherme Blanco
TEXT
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();
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();
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();
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
RULE #9
USE GETTERS AND SETTERS
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.
BENEFITS
▸ Operations injection
▸ Transformations encapsulation
▸ Promotes Open/Closed Principle ("O" in SOLID)
QUESTIONS?
THANKS! =)
GUILHERMEBLANCO
GUILHERMEBLANCO

More Related Content

What's hot

JavaScript Fetch API
JavaScript Fetch APIJavaScript Fetch API
JavaScript Fetch API
Xcat Liu
 
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
Rafael Dohms
 
Time-Based Blind SQL Injection using Heavy Queries
Time-Based Blind SQL Injection using Heavy QueriesTime-Based Blind SQL Injection using Heavy Queries
Time-Based Blind SQL Injection using Heavy Queries
Chema Alonso
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web APIhabib_786
 
You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)
andrewnacin
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
José Paumard
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
Joshua Long
 
Class 3 - PHP Functions
Class 3 - PHP FunctionsClass 3 - PHP Functions
Class 3 - PHP Functions
Ahmed Swilam
 
SQL Injection 101 : It is not just about ' or '1'='1 - Pichaya Morimoto
SQL Injection 101 : It is not just about ' or '1'='1 - Pichaya MorimotoSQL Injection 101 : It is not just about ' or '1'='1 - Pichaya Morimoto
SQL Injection 101 : It is not just about ' or '1'='1 - Pichaya Morimoto
Pichaya Morimoto
 
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшeQA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QAFest
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
L&T Technology Services Limited
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
Vladislav sidlyarevich
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017
Roman Elizarov
 
LPW: Beginners Perl
LPW: Beginners PerlLPW: Beginners Perl
LPW: Beginners Perl
Dave Cross
 
Object oreinted php | OOPs
Object oreinted php | OOPsObject oreinted php | OOPs
Object oreinted php | OOPs
Ravi Bhadauria
 
Data Types In PHP
Data Types In PHPData Types In PHP
Data Types In PHP
Mark Niebergall
 
Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018
Roman Elizarov
 
JAVA OOP
JAVA OOPJAVA OOP
JAVA OOP
Sunil OS
 
SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)
Bernardo Damele A. G.
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
Arturs Drozdovs
 

What's hot (20)

JavaScript Fetch API
JavaScript Fetch APIJavaScript Fetch API
JavaScript Fetch API
 
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
 
Time-Based Blind SQL Injection using Heavy Queries
Time-Based Blind SQL Injection using Heavy QueriesTime-Based Blind SQL Injection using Heavy Queries
Time-Based Blind SQL Injection using Heavy Queries
 
ASP.NET Web API
ASP.NET Web APIASP.NET Web API
ASP.NET Web API
 
You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)You Don't Know Query (WordCamp Netherlands 2012)
You Don't Know Query (WordCamp Netherlands 2012)
 
Java 8-streams-collectors-patterns
Java 8-streams-collectors-patternsJava 8-streams-collectors-patterns
Java 8-streams-collectors-patterns
 
REST APIs with Spring
REST APIs with SpringREST APIs with Spring
REST APIs with Spring
 
Class 3 - PHP Functions
Class 3 - PHP FunctionsClass 3 - PHP Functions
Class 3 - PHP Functions
 
SQL Injection 101 : It is not just about ' or '1'='1 - Pichaya Morimoto
SQL Injection 101 : It is not just about ' or '1'='1 - Pichaya MorimotoSQL Injection 101 : It is not just about ' or '1'='1 - Pichaya Morimoto
SQL Injection 101 : It is not just about ' or '1'='1 - Pichaya Morimoto
 
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшeQA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe
 
JavaScript Promises
JavaScript PromisesJavaScript Promises
JavaScript Promises
 
Introduction to java 8 stream api
Introduction to java 8 stream apiIntroduction to java 8 stream api
Introduction to java 8 stream api
 
Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017Introduction to Coroutines @ KotlinConf 2017
Introduction to Coroutines @ KotlinConf 2017
 
LPW: Beginners Perl
LPW: Beginners PerlLPW: Beginners Perl
LPW: Beginners Perl
 
Object oreinted php | OOPs
Object oreinted php | OOPsObject oreinted php | OOPs
Object oreinted php | OOPs
 
Data Types In PHP
Data Types In PHPData Types In PHP
Data Types In PHP
 
Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018Kotlin Coroutines in Practice @ KotlinConf 2018
Kotlin Coroutines in Practice @ KotlinConf 2018
 
JAVA OOP
JAVA OOPJAVA OOP
JAVA OOP
 
SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)SQL injection: Not Only AND 1=1 (updated)
SQL injection: Not Only AND 1=1 (updated)
 
JDBC - JPA - Spring Data
JDBC - JPA - Spring DataJDBC - JPA - Spring Data
JDBC - JPA - Spring Data
 

Viewers also liked

“Writing code that lasts” … or writing code you won’t hate tomorrow.
“Writing code that lasts” … or writing code you won’t hate tomorrow.“Writing code that lasts” … or writing code you won’t hate tomorrow.
“Writing code that lasts” … or writing code you won’t hate tomorrow.
Rafael Dohms
 
ORM dont kill your DB, developers do
ORM dont kill your DB, developers doORM dont kill your DB, developers do
ORM dont kill your DB, developers do
Guilherme Blanco
 
Realtime com node.js e socket.io
Realtime com node.js e socket.ioRealtime com node.js e socket.io
Realtime com node.js e socket.io
Caio Ribeiro Pereira
 
Thinking Object-Oriented
Thinking Object-OrientedThinking Object-Oriented
Thinking Object-Oriented
adil raja
 
PHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPPHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHP
Guilherme Blanco
 
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
Rafael Dohms
 
Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13Rafael Dohms
 
SPL Datastructures
SPL DatastructuresSPL Datastructures
SPL Datastructures
Felipe Ribeiro
 
Granny Was a Hacker (CampJS Version)
Granny Was a Hacker (CampJS Version)Granny Was a Hacker (CampJS Version)
Granny Was a Hacker (CampJS Version)
Kristine Howard
 
Introduction to Go programming
Introduction to Go programmingIntroduction to Go programming
Introduction to Go programming
Exotel
 

Viewers also liked (11)

“Writing code that lasts” … or writing code you won’t hate tomorrow.
“Writing code that lasts” … or writing code you won’t hate tomorrow.“Writing code that lasts” … or writing code you won’t hate tomorrow.
“Writing code that lasts” … or writing code you won’t hate tomorrow.
 
ORM dont kill your DB, developers do
ORM dont kill your DB, developers doORM dont kill your DB, developers do
ORM dont kill your DB, developers do
 
Realtime com node.js e socket.io
Realtime com node.js e socket.ioRealtime com node.js e socket.io
Realtime com node.js e socket.io
 
Thinking Object-Oriented
Thinking Object-OrientedThinking Object-Oriented
Thinking Object-Oriented
 
PHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPPHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHP
 
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
 
Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13Your code sucks, let's fix it! - php|tek13
Your code sucks, let's fix it! - php|tek13
 
SPL Datastructures
SPL DatastructuresSPL Datastructures
SPL Datastructures
 
RESTful API Design, Second Edition
RESTful API Design, Second EditionRESTful API Design, Second Edition
RESTful API Design, Second Edition
 
Granny Was a Hacker (CampJS Version)
Granny Was a Hacker (CampJS Version)Granny Was a Hacker (CampJS Version)
Granny Was a Hacker (CampJS Version)
 
Introduction to Go programming
Introduction to Go programmingIntroduction to Go programming
Introduction to Go programming
 

Similar to PHP for Adults: Clean Code and Object Calisthenics

Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
Sam Hennessy
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
Yuya Takeyama
 
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
XSolve
 
Oops in php
Oops in phpOops in php
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
Rifat Nabi
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
Pete McFarlane
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
Hugo Hamon
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
Hugo Hamon
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
Hugo Hamon
 
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
Rafael Dohms
 
Functional programming with php7
Functional programming with php7Functional programming with php7
Functional programming with php7
Sérgio Rafael Siqueira
 
Anonymous classes
Anonymous classesAnonymous classes
Anonymous classes
Darkmira
 
1st CI&T Lightning Talks: Writing better code with Object Calisthenics
1st CI&T Lightning Talks: Writing better code with Object Calisthenics1st CI&T Lightning Talks: Writing better code with Object Calisthenics
1st CI&T Lightning Talks: Writing better code with Object Calisthenics
Lucas Arruda
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
Abbas Ali
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
Hugo Hamon
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHPTaras Kalapun
 
“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...
“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...
“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...
DevClub_lv
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
Jeff Carouth
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
Jace Ju
 

Similar to PHP for Adults: Clean Code and Object Calisthenics (20)

Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
PHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くためにPHPUnit でよりよくテストを書くために
PHPUnit でよりよくテストを書くために
 
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
 
Oops in php
Oops in phpOops in php
Oops in php
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
How to write code you won't hate tomorrow
How to write code you won't hate tomorrowHow to write code you won't hate tomorrow
How to write code you won't hate tomorrow
 
Design Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et PimpleDesign Patterns avec PHP 5.3, Symfony et Pimple
Design Patterns avec PHP 5.3, Symfony et Pimple
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
 
Database Design Patterns
Database Design PatternsDatabase Design Patterns
Database Design Patterns
 
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
 
Functional programming with php7
Functional programming with php7Functional programming with php7
Functional programming with php7
 
Anonymous classes
Anonymous classesAnonymous classes
Anonymous classes
 
1st CI&T Lightning Talks: Writing better code with Object Calisthenics
1st CI&T Lightning Talks: Writing better code with Object Calisthenics1st CI&T Lightning Talks: Writing better code with Object Calisthenics
1st CI&T Lightning Talks: Writing better code with Object Calisthenics
 
Tidy Up Your Code
Tidy Up Your CodeTidy Up Your Code
Tidy Up Your Code
 
The History of PHPersistence
The History of PHPersistenceThe History of PHPersistence
The History of PHPersistence
 
Crazy things done on PHP
Crazy things done on PHPCrazy things done on PHP
Crazy things done on PHP
 
Shell.php
Shell.phpShell.php
Shell.php
 
“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...
“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...
“SOLID principles in PHP – how to apply them in PHP and why should we care“ b...
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 

More from Guilherme Blanco

Enterprise php
Enterprise phpEnterprise php
Enterprise php
Guilherme Blanco
 
PHP 7
PHP 7PHP 7
Javascript para adultos
Javascript para adultosJavascript para adultos
Javascript para adultos
Guilherme Blanco
 
Dependency injection
Dependency injectionDependency injection
Dependency injection
Guilherme Blanco
 
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHPIPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
Guilherme Blanco
 
Doctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHPDoctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHP
Guilherme Blanco
 
PHP, Daemons e Multimedia
PHP, Daemons e MultimediaPHP, Daemons e Multimedia
PHP, Daemons e Multimedia
Guilherme Blanco
 
Doctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHPDoctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHP
Guilherme Blanco
 
Desenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmDesenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine Orm
Guilherme Blanco
 

More from Guilherme Blanco (10)

Enterprise php
Enterprise phpEnterprise php
Enterprise php
 
PHP 7
PHP 7PHP 7
PHP 7
 
Javascript para adultos
Javascript para adultosJavascript para adultos
Javascript para adultos
 
Dependency injection
Dependency injectionDependency injection
Dependency injection
 
Doctrine2 Seminário PHP
Doctrine2 Seminário PHPDoctrine2 Seminário PHP
Doctrine2 Seminário PHP
 
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHPIPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
IPC2010SE Doctrine2 Enterprise Persistence Layer for PHP
 
Doctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHPDoctrine 2.0: A evolução da persistência em PHP
Doctrine 2.0: A evolução da persistência em PHP
 
PHP, Daemons e Multimedia
PHP, Daemons e MultimediaPHP, Daemons e Multimedia
PHP, Daemons e Multimedia
 
Doctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHPDoctrine 2.0 Enterprise Persistence Layer for PHP
Doctrine 2.0 Enterprise Persistence Layer for PHP
 
Desenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmDesenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine Orm
 

Recently uploaded

Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Product School
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
Jemma Hussein Allen
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 

Recently uploaded (20)

Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...Designing Great Products: The Power of Design and Leadership by Chief Designe...
Designing Great Products: The Power of Design and Leadership by Chief Designe...
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
The Future of Platform Engineering
The Future of Platform EngineeringThe Future of Platform Engineering
The Future of Platform Engineering
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 

PHP for Adults: Clean Code and Object Calisthenics

  • 1. PHP 4 ADULTS OBJECT CALISTHENICS AND CLEAN CODE
  • 5.
  • 7. S T U P I D
  • 9. S O L I D
  • 10. SINGLE RESPONSIBILITY OPEN/CLOSED PRINCIPLE LISKOV SUBSTITUTION PRINCIPLE INTERFACE SEGREGATION DEPENDENCY INVERSION
  • 12. interface Bird { public function setLocation($longitude, $latitude); public function setHeight($height); public function draw(); }
  • 13. class Penguin implements Bird { public function setHeight($height) { // Do nothing } }
  • 14. interface Bird { public function setLocation($longitude, $latitude); public function draw(); } interface FlightfulBird extends Bird 
 { 
 public function setHeight($height); }
  • 16. namespace DatingUserBundleEntity { class User { /** @var DatingUserBundleEntityImage */ protected $avatar; } } namespace DatingMediaBundleEntity { class Image { /** @var DatingUserBundleEntityUser */ protected $owner; } 
 }
  • 17. namespace DatingUserBundleEntity { class User { /** @var AvatarInterface */ protected $avatar; } interface AvatarInterface { // ... } } namespace DatingMediaBundleEntity { use DatingUserBundleEntityAvatarInterface; class Image implements AvatarInterface { /** @var DatingUserBundleEntityUser */ protected $owner; } 
 }
  • 19. RULE #1 ONLY ONE INDENTATION LEVEL PER METHOD
  • 20. 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; }
  • 21. 1 2 3 4 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
  • 23. 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; }
  • 24. 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; }
  • 25. 1 2 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; }
  • 26. 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; }
  • 27. 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; }
  • 28. 1 2 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; }
  • 29. 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; }
  • 30. 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
  • 31. 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; }
  • 32. BENEFITS ▸ Single Responsibility Principle ("S" in SOLID) ▸ Reusability
  • 33. RULE #2 NO "ELSE" KEYWORD
  • 34. 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); } }
  • 35. 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!
  • 36. 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); } }
  • 37. 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); } }
  • 38. 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); } }
  • 40. 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); } }
  • 41. 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); } }
  • 42. 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); } }
  • 43. 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); } }
  • 44. 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); } }
  • 45. 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); } }
  • 46. 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'); }
  • 47. 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'); }
  • 48. BENEFITS ▸ Prevents code duplication ▸ Increases legibility ▸ Reduce cyclomatic complexity
  • 49. RULE #3 ENCAPSULATE ALL PRIMITIVE TYPES AND STRINGS
  • 50. RULE #3 ENCAPSULATE ALL PRIMITIVE TYPES AND STRINGS IF THEY HAVE BEHAVIOR
  • 52. EXCESSIVE USAGE OF OBJECTS IN PHP (IF PHP <7!) DRASTICALLY INCREASES MEMORY FOOTPRINT! Guilherme Blanco
  • 53. 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 ... } }
  • 54. 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 ... } }
  • 55. 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 ... } }
  • 56. 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; } }
  • 57. class Item { final public static function find(Id $id) { // do find ... } final public static function create(Id $id, array $data) { // do create ... } }
  • 58. BENEFITS ▸ Type hinting ▸ Encapsulation ▸ Prevents code duplication
  • 59. RULE #4 ONE OBJECT OPERATOR (->) PER LINE
  • 61. JUST USE A NULL OBJECT! Someone watching this talk, one day
  • 62. 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'; } }
  • 63. 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
  • 64. EXCEPTION TO RULE FLUENT INTERFACE UNDER SAME METHOD
  • 66. BENEFITS ▸ Law of Demeter ▸ Readability ▸ Increases testability (easier to mock) ▸ Simplifies debugging
  • 67. RULE #5 DO NOT ABBREVIATE
  • 68. THERE ARE 2 HARD PROBLEMS IN COMPUTER SCIENCE: CACHE INVALIDATION, NAMING THINGS AND OFF BY 1 ERRORS. Tim Bray (mentioning Phil Karlton)
  • 70. CODE DUPLICATION PROBLEM! WRITE SAME NAME REPEATEDLY
  • 72. public function getPage($data) { ... } "Get" from where? public function startProcess() { ... } $trx->process('site.login'); How? WTF is that? renderHomePage forkIntoChildProcess extendedTranslator
  • 73. BENEFITS ▸ Readability ▸ Better exposing method’s intent ▸ Improved maintainability ▸ Good indicator of code duplication and encapsulation
  • 74. RULE #6 KEEP YOUR CLASSES SMALL
  • 75. 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
  • 76. BENEFITS ▸ Single Responsibility Principle ▸ Clear and objective methods ▸ Better code segregation ▸ Cleaner namespaces
  • 77. RULE #7 LIMIT CLASS INSTANCE VARIABLES IN A CLASS (BETWEEN 2 TO 5)
  • 78. 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
  • 79. class MyRegistrationService implements LoggerAwareInterface, TranslatorAwareInterface { use LoggerAwareTrait; use TranslatorAwareTrait; protected $userService; protected $passwordService; protected $eventDispatcher; // ... }
  • 80. BENEFITS ▸ Single Responsibility Principle ▸ Loose coupling ▸ Better encapsulation ▸ Testability
  • 81. RULE #8 USE FIRST CLASS COLLECTIONS
  • 83. ANY CLASS THAT CONTAINS AN ARRAY MUST NOT HAVE ANY OTHER PROPERTY. Guilherme Blanco TEXT
  • 84. 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();
  • 85. 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();
  • 86. 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();
  • 87. 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
  • 88. RULE #9 USE GETTERS AND SETTERS
  • 89. 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.
  • 90. BENEFITS ▸ Operations injection ▸ Transformations encapsulation ▸ Promotes Open/Closed Principle ("O" in SOLID)