gérer vos objets
DESCRIPTION
Après une discution animée autour de concepts objets lors du dernier Apéro PHP de Montpellier, je me suis aperçu qu'un petit rappel des bases de la POO était nécessaire. En 10 minutes, retour sur des concepts comme l'Injection de dépendances et sur certains design patterns (factory, singleton). Le tout illustré avec des exemples en PHP.TRANSCRIPT
Case study
/* ask name */fwrite(STDOUT, "enter your name :");$name = trim(fgets(STDIN, 255));
/* ask birthday */fwrite(STDOUT, "enter your birthday (yyyy/mm/dd) :");$birthday = new DateTime(trim(fgets(STDIN, 255)));
/* calculate the age */$age = $birthday->diff(new DateTime());
/* display the result */fwrite(
STDOUT,sprintf(PHP_EOL."hello %s you've got %s years old.", $name, $age->y)
);
Oriented Object Programing
Application Class Diagram
Reader
+ handle+ length
+ read(msg)
Writer
+ handle
+ write(msg)
AgeCalculator
+ execute()
// src/Reader.php
class Reader{
private $handle = STDIN;private $length = 255;private $writer;
public function __construct(){
$this->writer = new Writer();}
public function read($msg){
$this->writer->write($msg);return trim(fgets($this->handle, $this->length));
}}
// src/AgeCalculator.php
class AgeCalculator{
private $reader, $writer;
public function __construct(){
$this->reader = new Reader();$this->writer = new Writer();
}
public function execute(){
$name = $this->reader->read('your name:');$birthday = new DateTime(
$this->reader->read('your birthday (yyyy/mm/dd):'));$age = $birthday->diff(new DateTime('now'));$this->writer->write(
sprintf("hello %s you've got %s years old.", $name, $age->y));
}}
Running the application
// age-calculator.php
$ageCalculator = new AgeCalculator();$ageCalculator->execute();
$ php age-calculator.phpyour name: thomasyour birthday (yyyy/mm/dd): 1994/01/01hello thomas you've got 20 years old.
Dependency Injection
Pass a dependency to a dependent object
// src/Reader.php
class Reader{
private $handle, $length, $writer;
public function __construct(Writer $writer = null, $handle = STDIN, $length = 255){
$this->handle = $handle;$this->length = $length;$this->writer = $writer;
}
public function read($msg){
if ($this->writer) {$this->writer->write($msg);
}return trim(fgets($this->handle, $this->length));
}}
// age-calculator.php
$writer = new Writer();$reader = new Reader($writer);$ageCalculator = new AgeCalculator($writer, $reader);$ageCalculator->execute();
// age-calculator.php
$writer = new Writer(fopen('result', 'w+'));$reader = new Reader(null, fopen('data', 'r'));$ageCalculator = new AgeCalculator($writer, $reader);$ageCalculator->execute();
Using a Dependency Injection Framework
// config/cli.php
return [
'Writer' => DI\object()->constructor(),
'Reader' => DI\object()->constructor(DI\link('Writer')),
'AgeCalculator' => DI\object()->constructor(DI\link('Writer'), DI\link('Reader')),
];
// age-calculator.php
require 'vendor/autoload.php';
$builder = new \DI\ContainerBuilder();$builder->addDefinitions('config/cli.php');
$container = $builder->build();
$ageCalculator = $container->get('AgeCalculator');$ageCalculator->execute();
// config/file.php
return [
'handle.result' => fopen('result', 'w+'),'handle.data' => fopen('data', 'r'),
'Writer' => DI\object() ->constructor(DI\link('handle.result')),
'Reader' => DI\object() ->constructor(null, DI\link('handle.data')),
'AgeCalculator' => DI\object() ->constructor(DI\link('Writer'), DI\link('Reader')),
];
Factory Design Pattern
Deals with the problem of creating objects without specifying the exact class of object that will be created
<< abstract >>
Factory
+ create()
WriterFactoryReaderFactory
FileWriter
WriterReader
FileReader
<< interface >>
ReaderInterface<< interface >>
WriterInterface
creates creates
extends extends
extends extends
uses
extends extends
+ setWriter(writer)+ read(msg)
+ write(msg)
// src/FileWriter.php
class FileWriter extends Writer{
public function __construct($filename, $length = 255){
$this->handle = fopen($filename, 'w+');$this->length = $length;
}}
// src/Filereader.php
class FileReader extends Reader{
public function __construct($filename, $length = 255){
$this->handle = fopen($filename, 'r');$this->length = $length;
}}
// src/Factory.php
abstract class Factory{
private $class;
public function __construct($class){
$this->class = new ReflectionClass($class);}
protected abstract function configure(ReflectionClass $class);
public function create($args = array()){
return $this->class->newInstanceArgs($args);}
}
// config/file.php
return ['writer.class' => 'FileWriter','reader.class' => 'FileReader','data.file' => 'data','result.file' => 'result','WriterFactory' => DI\object()->constructor(DI\link('writer.class')),'ReaderFactory' => DI\object()
->constructor(DI\link('reader.class')), DI\factory(function ($container) {
return $container->get('WriterFactory')->create(array($container->get('result.file')))
;}),DI\factory(function ($container) {
return $container->get('ReaderFactory')->create(array($container->get('data.file')))
;}
),'AgeCalculator' => DI\object()->constructor(DI\link('writer'), DI\link('reader')),
];
Singleton Design Pattern
Restricts the instantiation of a class to one object
Singleton
Full examples
https://github.com/methylbro/human-talk-manage-objects-examples
Questions ?