Je suis le susnommé Kevin Nadin
Twitter : @kevinjhappy
Je travaille à Darkmira en tant que développeur PHP, c'est une boîte avec plein de dev cools ;)
(bon, en même temps, c'est le titre de la conf... )
<?php
class Warrior
{
private $lifePoint;
private $hitPoint;
public function __construct(int $lifePoint, int $hitPoint)
{
$this->lifePoint = $lifePoint;
$this->hitPoint = $hitPoint;
}
}
<?php
class Warrior
{
// ...
public function isAlive(): bool
{
return 0 <= $this->lifePoint;
}
public function attack(): int
{
if ($this->isAlive()) {
return $this->hitPoint;
}
return 0;
}
public function takeDamage(int $damage): void
{
$this->lifePoint -= $damage;
}
}
<?php
// je recois les données en tableau, mais je ne sais pas dans quel ordre
$entryData = [
[
'type' => 'Warrior',
'lifePoint' => 20,
'hitPoint' => 5,
],
[
'type' => 'Warrior',
'lifePoint' => 15,
'hitPoint' => 8,
]
];
// je crée le premier personnage
$data = $entryData[0];
if ('Warrior' === $data['type']) {
$firstCharacter = new Warrior($data['lifePoint'], $data['hitPoint']);
}
// je crée le second personnage
$data = $entryData[1];
if ('Warrior' === $data['type']) {
$secondCharacter = new Warrior($data['lifePoint'], $data['hitPoint']);
}
// Battle
while ($secondCharacter->isAlive() && $firstCharacter->isAlive()) {
$secondCharacter->takeDamage($firstCharacter->attack());
$firstCharacter->takeDamage($secondCharacter->attack());
}
if (!$secondCharacter->isAlive()) {
echo 'Victory to the first character';
} elseif (!$firstCharacter->isAlive()) {
echo 'Victory to the second character';
}
class Warrior
{
private $lifePoint;
private $hitPoint;
public function __construct(int $lifePoint, int $hitPoint)
{
//...
}
//...
public static function create(array $data): self
{
return new Warrior($data['lifePoint'] ?? 1, $data['hitPoint'] ?? 1);
}
}
// je crée le premier personnage
$data = $entryData[0];
if ('Warrior' === $data['type']) {
$firstCharacter = Warrior::create($data);
}
// je crée le second personnage
$data = $entryData[1];
if ('Warrior' === $data['type']) {
$secondCharacter = Warrior::create($data);
}
<?php
class Wizard
{
private $lifePoint;
private $hitPoint;
private $magicPoint;
public function __construct(int $lifePoint, int $hitPoint, int $magicPoint)
{
$this->lifePoint = $lifePoint;
$this->hitPoint = $hitPoint;
$this->magicPoint = $magicPoint;
}
}
<?php
class Wizard
{
// ...
public function isAlive(): bool
{
return 0 <= $this->lifePoint;
}
public function attackWithMagic(): int
{
if ($this->isAlive() && $this->magicPoint >= 2 ) {
$this->magicPoint -= 2;
return $this->hitPoint;
}
return 0;
}
public function takeDamage(int $damage): void
{
$this->lifePoint -= $damage;
}
}
<?php
class Wizard
{
// ...
public static function create(array $data): self
{
// on peut aussi utiliser le mot clé self au lieu de Wizard
return new self(
$data['lifePoint'] ?? 1,
$data['hitPoint'] ?? 1,
$data['magicPoint'] ?? 1
);
}
}
<?php
$entryData = [
[
'type' => 'Warrior',
'lifePoint' => 20,
'hitPoint' => 5,
],
[
'type' => 'Wizard',
'lifePoint' => 15,
'hitPoint' => 8,
'manaPoint' => 10,
]
];
// je crée le premier personnage
$data = $entryData[0];
switch ($data['type']) {
case 'Warrior':
$firstCharacter = Warrior::create($data);
break;
case 'Wizard':
$firstCharacter = Wizard::create($data);
break;
}
// je crée le second personnage
$data = $entryData[1];
switch ($data['type']) {
case 'Warrior':
$secondCharacter = Warrior::create($data);
break;
case 'Wizard':
$secondCharacter = Wizard::create($data);
break;
}
// Battle
while ($secondCharacter->isAlive() && $firstCharacter->isAlive()) {
if ($firstCharacter instanceof Wizard) {
$secondCharacter->takeDamage($firstCharacter->attackWithMagic());
} else {
$secondCharacter->takeDamage($firstCharacter->attack());
}
if ($secondCharacter instanceof Wizard) {
$firstCharacter->takeDamage($secondCharacter->attackWithMagic());
} else {
$firstCharacter->takeDamage($secondCharacter->attack());
}
}
if (!$secondCharacter->isAlive()) {
echo 'victory to the first character';
} elseif (!$firstCharacter->isAlive()) {
echo 'victory to the second character';
}
Pour être certain du type de l'objet, on doit vérifier les types à chaque fois
Une fois, deux fois, .... et on se retrouve à le faire partout dans le projet.
De plus, si on ajoute un autre type de personnage, on doit modifier tous les switch concernés.
<?php
class FightingCharactersFactory
{
public static function create(string $parameter, array $data)
{
switch ($parameter) {
case 'Warrior':
return new Warrior($data['lifePoint'], $data['hitPoint']);
case 'Wizard':
return new Wizard($data['lifePoint'],
$data['hitPoint'], $data['manaPoint']);
}
}
}
<?php
interface CanBattleInterface
{
public function isAlive(): bool;
public function attack(): int;
public function takeDamage(int $damage): void;
}
class Warrior implements CanBattleInterface
{
private $lifePoint;
private $hitPoint;
public function __construct(int $lifePoint, int $hitPoint)
{
$this->lifePoint = $lifePoint;
$this->hitPoint = $hitPoint;
}
public function isAlive(): bool
{
//...
}
public function attack(): int
{
//...
}
public function takeDamage(int $damage): void
{
//...
}
}
class Wizard implements CanBattleInterface
{
private $lifePoint;
private $hitPoint;
private $magicPoint;
public function __construct(int $lifePoint, int $hitPoint, int $magicPoint)
{
$this->lifePoint = $lifePoint;
$this->hitPoint = $hitPoint;
$this->magicPoint = $magicPoint;
}
public function isAlive(): bool
{
//...
}
// attackWithMagic() devient simplement attack()
public function attack(): int
{
//...
}
public function takeDamage(int $damage): void
{
//...
}
}
<?php
class FightingCharactersFactory
{
public static function create(string $parameter, array $data): CanBattleInterface
{
switch ($parameter) {
case 'Warrior':
return new Warrior($data['lifePoint'], $data['hitPoint']);
case 'Wizard':
return new Wizard($data['lifePoint'],
$data['hitPoint'], $data['manaPoint']);
}
}
}
<?php
final class FightingCharactersFactory
{
public static function create(string $parameter, array $data): CanBattleInterface
{
switch ($parameter) {
case 'Warrior':
return new Warrior($data['lifePoint'], $data['hitPoint']);
case 'Wizard':
return new Wizard($data['lifePoint'],
$data['hitPoint'], $data['manaPoint']);
default:
throw new \Exception();
}
}
}
<?php
class UnknownCharacterTypeException extends InvalidArgumentException
{
private const MESSAGE = 'Invalid character type : %s';
public function __construct(string $parameter, $code = 0,
Throwable $previous = null)
{
parent::__construct(sprintf(self::MESSAGE, $parameter), $code, $previous);
}
}
<?php
final class FightingCharactersFactory
{
public static function create(string $parameter, array $data): CanBattleInterface
{
switch ($parameter) {
case 'Warrior':
return new Warrior($data['lifePoint'], $data['hitPoint']);
case 'Wizard':
return new Wizard($data['lifePoint'],
$data['hitPoint'], $data['manaPoint']);
default:
throw new UnknownCharacterTypeException($parameters);
}
}
}
<?php
// je recois les données en tableau, mais je ne sais pas dans quel ordre
$entryData = [
[
'type' => 'Warrior',
'lifePoint' => 20,
'hitPoint' => 5,
],
[
'type' => 'Wizard',
'lifePoint' => 15,
'hitPoint' => 8,
'manaPoint' => 10,
]
];
$characters = [];
foreach ($entryData as $data) {
$characters[] = FightingCharactersFactory::create($data['type'], $data);
}
// Battle
while ($characters[0]->isAlive() && $characters[1]->isAlive()) {
$characters[1]->takeDamage($characters[0]->attack());
$characters[0]->takeDamage($characters[1]->attack());
}
if (!$characters[1]->isAlive()) {
echo 'victory to the first character';
} elseif (!$characters[0]->isAlive()) {
echo 'victory to the second character';
}
<?php
$characters = [];
foreach ($entryData as $data) {
$characters[] = FightingCharactersFactory::create($data['type'], $data);
}
// tous les éléments de $characters sont des objet de type CanBattleInterface
/** @var CanBattleInterface[] $characters */
while ($characters[0]->isAlive() && $characters[1]->isAlive()) {
$characters[1]->takeDamage($characters[0]->attack());
$characters[0]->takeDamage($characters[1]->attack());
}
class Archer implements CanBattleInterface
{
private $lifePoint;
private $hitPoint;
private $arrowNumber;
public function __construct(int $lifePoint, int $hitPoint, int $arrowNumber)
{
$this->lifePoint = $lifePoint;
$this->hitPoint = $hitPoint;
$this->arrowNumber = $arrowNumber;
}
public function isAlive(): bool
{
//...
}
public function attack(): int
{
//...
}
public function takeDamage(int $damage): void
{
//...
}
}
<?php
final class FightingCharactersFactory
{
public static function create(string $parameter, array $data): CanBattleInterface
{
switch ($parameter) {
case 'Warrior':
return new Warrior($data['lifePoint'], $data['hitPoint']);
case 'Wizard':
return new Wizard($data['lifePoint'],
$data['hitPoint'], $data['manaPoint']);
case 'Archer':
return new Archer($data['lifePoint'],
$data['hitPoint'], $data['arrowNumber']);
default:
throw new UnknownCharacterTypeException($parameter);
}
}
}