collect[$key] = $value;
}
public function all(): array
{
return $this->collect;
}
}
Slide 18
Slide 18 text
collect[$key] = $value;
}
public function all(): array
{
return $this->collect;
}
}
ෆ࣮֬ͳܕͷࠞೖΛ͙ͨΊ
ೖྗΛ੍ݶ
Slide 19
Slide 19 text
collect[$key] = $value;
}
public function all(): array
{
return $this->collect;
}
}
੍ޚෆՄ
Slide 20
Slide 20 text
class ExtendArraySet extends ArraySet
{
public function all(): array
{
$this->collect[1] = 2;
return $this->collect;
}
}
੍ޚෆՄ
Slide 21
Slide 21 text
No content
Slide 22
Slide 22 text
$collect = [];
public function add(string $key, string $value): void {
$this->collect[$key] = $value;
}
public function all(): darray {
return $this->collect;
}
}
Slide 23
Slide 23 text
$collect = [];
public function add(string $key, string $value): void {
$this->collect[$key] = $value;
}
public function all(): darray {
return $this->collect;
}
}
ෆ࣮֬ͳܕͷࠞೖΛ͙ͨΊ
ೖྗΛ੍ݶ
Slide 24
Slide 24 text
$collect = [];
public function add(string $key, string $value): void {
$this->collect[$key] = $value;
}
public function all(): darray {
return $this->collect;
}
}
ܧঝ࣌Ͱͦͷ··੍ޚՄ
Slide 25
Slide 25 text
class ExtendArraySet extends ArraySet
{
public function all(): darray
{
$this->collect[1] = 2;
return $this->collect;
}
} ૠೖෆՄ
Slide 26
Slide 26 text
class ExtendArraySet extends ArraySet
{
public function all(): darray
{
$this->collect[1] = 2;
return $this->collect;
}
}
ΓͷܕΛมߋ͢Δ͜ͱෆՄ
Slide 27
Slide 27 text
src/ArraySet.php:19:5,25: Invalid assignment (Typing[4110])
src/ArraySet.php:5:20,25: This is a string
src/ArraySet.php:19:20,20: It is incompatible with an int
src/ArraySet.php:20:12,25: Invalid return type (Typing[4110])
src/ArraySet.php:18:33,38: This is a string
src/ArraySet.php:19:20,20: It is incompatible with an int
Slide 28
Slide 28 text
public function merge(): darray {
$a = new ArraySet();
$a->add('PHP', 'Arrays');
$ar = $a->all();
$ar[1] = 11;
return $ar;
}
औಘޙɺ
ҟͳΔܕͷΛࠞೖͤ͞Δ͜ͱՄೳ
*ΓͷܕΛఆٛ͢Δ͜ͱ
abstract final class dict<+Tk as arraykey, +Tv>
implements Indexish, XHPChild {}
abstract final class keyset<+T as arraykey>
implements Indexish, XHPChild {}
abstract final class vec<+T>
implements Indexish, XHPChild {}
namespace Acme\Shapes;
type SampleShape = shape(
'a' => int,
'b' => int
);
type NestShape = shape(
'sample' => SampleShape,
'vec' => vec
);
class NestedShape {
public function nest(): NestShape {
return shape(
'sample' => shape(
'a' => 0,
'b' => 1
),
'vec' => vec[
'shapes'
],
);
}
}
Shapesಉ࢜ΛΈ߹Θͤͯ
ఆٛՄ
Slide 58
Slide 58 text
The field 'z' is not defined in this shape type,
and this shape type does not allow unknown fields.
The field 'z' is set in the shape.
ఆٛ͞Ε͍ͯͳ͍ϑΟʔϧυ
ར༻࣌ʹΤϥʔ
<<__Rx>>
public function getInstance(classname $t): T {
return $this->resolve($t);
}
<<__Memoize>>
protected function shared(classname $id): T {
list($_, $callable) = $this->map[$id];
return $callable($this);
}
<<__Rx>>
public function has(string $id): bool {
return C\contains_key($this->map, $id);
}
Slide 80
Slide 80 text
<<__Rx>>
public function getInstance(classname $t): T {
return $this->resolve($t);
}
<<__Memoize>>
protected function shared(classname $id): T {
list($_, $callable) = $this->map[$id];
return $callable($this);
}
<<__Rx>>
public function has(string $id): bool {
return C\contains_key($this->map, $id);
}
hhvm/hsl
array_key_existsϥούʔؔ
Slide 81
Slide 81 text
<<__Rx>>
public function getInstance(classname $t): T {
return $this->resolve($t);
}
<<__Memoize>>
protected function shared(classname $id): T {
list($_, $callable) = $this->map[$id];
return $callable($this);
}
<<__Rx>>
public function has(string $id): bool {
return C\contains_key($this->map, $id);
}
ϝϞԽࢦఆ
ҾΛར༻ͯ͠Ωϟογϡ͞ΕΔ
γϯάϧτϯ
Slide 82
Slide 82 text
<<__Rx>>
public function getInstance(classname $t): T {
return $this->resolve($t);
}
<<__Memoize>>
protected function shared(classname $id): T {
list($_, $callable) = $this->map[$id];
return $callable($this);
}
<<__Rx>>
public function has(string $id): bool {
return C\contains_key($this->map, $id);
}
reactiveʹ
Slide 83
Slide 83 text
<<__Rx>>
protected function resolve(classname $id): T {
if ($this->has($id)) {
list($scope, $callable) = $this->map[$id];
if ($callable is nonnull) {
if ($scope === Scope::SINGLETON) {
return $this->shared($id);
}
return $callable($this);
}
}
throw new Exception\NotFoundException(
Str\format('Identifier "%s" is not binding.', $id),
);
}
Slide 84
Slide 84 text
<<__Rx>>
protected function resolve(classname $id): T {
if ($this->has($id)) {
list($scope, $callable) = $this->map[$id];
if ($callable is nonnull) {
if ($scope === Scope::SINGLETON) {
return $this->shared($id);
}
return $callable($this);
}
}
throw new Exception\NotFoundException(
Str\format('Identifier "%s" is not binding.', $id),
);
}
nullͰͳ͍͔Ͳ͏͔
Slide 85
Slide 85 text
<<__Rx>>
protected function resolve(classname $id): T {
if ($this->has($id)) {
list($scope, $callable) = $this->map[$id];
if ($callable is nonnull) {
if ($scope === Scope::SINGLETON) {
return $this->shared($id);
}
return $callable($this);
}
}
throw new Exception\NotFoundException(
Str\format('Identifier "%s" is not binding.', $id),
);
}
γϯάϧτϯͷ߹ɺ
ϝϞԽ
trait MessageTrait {
require implements RequestInterface;
private dict> $headers = dict[];
public function castIntVersion(): int {
return (int) $this->getVersion();
}
}
Slide 104
Slide 104 text
trait MessageTrait {
require implements RequestInterface;
private dict> $headers = dict[];
public function castIntVersion(): int {
return (int) $this->getVersion();
}
}
ϦΫΤετΫϥεͷϝιουΛ
ར༻͍ͨ͠
Slide 105
Slide 105 text
src/MessageTrait.php:10:25,34: Could not find method getVersion
in an object of type Acme\MessageTrait (Typing[4053])
src/MessageTrait.php:10:18,22: This is why I think it is an
object of type Acme\MessageTrait
src/MessageTrait.php:5:7,18: Declaration of Acme\MessageTrait
is here
ΠϯλʔϑΣʔεʹఆٛ͞Ε͍ͯͳ͍
ϝιουίʔϧෆՄ
{
public function __construct(
private T $id
) {}
<<__Rx>>
public function id(): T {
return $this->id;
}
<<__Rx>>
public function equals(Identifier $id): bool {
return $this->id === $id->id();
}
}
Slide 118
Slide 118 text
{
public function __construct(
private T $id
) {}
<<__Rx>>
public function id(): T {
return $this->id;
}
<<__Rx>>
public function equals(Identifier $id): bool {
return $this->id === $id->id();
}
}
ҾΓͰར༻͢ΔܕΛҰͭʹ
Slide 119
Slide 119 text
{
public function __construct(
private T $id
) {}
<<__Rx>>
public function id(): T {
return $this->id;
}
<<__Rx>>
public function equals(Identifier $id): bool {
return $this->id === $id->id();
}
}
int
int
int
int
namespace Acme\Domain\Model\Article\Entity;
use type DateTime;
use type Acme\Domain\Model\EntityInterface;
use type Acme\Domain\Model\Article\ArticleId;
use type Acme\Domain\Model\Article\Body;
class Article implements EntityInterface {
const int EXPIRE_EDIT_TIME = 120;
public function __construct(
private ArticleId $id,
private Body $body,
private DateTime $createdAt = new DateTime()
) {}
<<__Rx>>
public function getID(): T {
return $this->id->id();
} // লུ
}
Slide 124
Slide 124 text
namespace Acme\Domain\Model\Article\Entity;
use type DateTime;
use type Acme\Domain\Model\EntityInterface;
use type Acme\Domain\Model\Article\ArticleId;
use type Acme\Domain\Model\Article\Body;
class Article implements EntityInterface {
const int EXPIRE_EDIT_TIME = 120;
public function __construct(
private ArticleId $id,
private Body $body,
private DateTime $createdAt = new DateTime()
) {}
<<__Rx>>
public function getID(): T {
return $this->id->id();
} // লུ
}
୯ҰͷܕͷΈ
ޡͬͨܕ͕հೖͮ͠Β͍
(TypecheckerͰݕ)
interface ArticleRepositoryInterface {
public function add(T $entity): void;
public function remove(T $entity): void;
public function findById(TId $id): T;
public function latestArticles(DateTime $date): Map $specification
): Map;
public function size(): int;
}
Slide 128
Slide 128 text
interface ArticleRepositoryInterface {
public function add(T $entity): void;
public function remove(T $entity): void;
public function findById(TId $id): T;
public function latestArticles(DateTime $date): Map $specification
): Map;
public function size(): int;
}
TId : Identifierintಛఆͷܕ͔Ͳ͏͔ɻɻʁ
T: EntityͰ͋Δ͕ɺ͜ͷϦϙδτϦͰѻ͏ͷશͯಉ͡ܕ
Slide 129
Slide 129 text
ϦϙδτϦ ࣮
*DDDࣗମͷΛ͢ΔΘ͚Ͱແ͍ͷͰৄࡉׂѪ
Slide 130
Slide 130 text
abstract class BaseRepository>
implements ArticleRepositoryInterface {
protected Map $collect = Map{};
public function add(T $article): void {
$this->collect->add(Pair{$article->getID(), $article});
}
// লུ
<<__Rx>>
public function findById(TId $id): T {
if($this->collect->contains($id)) {
return $this->collect->at($id);
}
throw new \RuntimeException('Not Found.');
}
}
Slide 131
Slide 131 text
abstract class BaseRepository>
implements ArticleRepositoryInterface {
protected Map $collect = Map{};
public function add(T $article): void {
$this->collect->add(Pair{$article->getID(), $article});
}
// লུ
<<__Rx>>
public function findById(TId $id): T {
if($this->collect->contains($id)) {
return $this->collect->at($id);
}
throw new \RuntimeException('Not Found.');
}
}
TId : Identifierintಛఆͷܕ͔Ͳ͏͔ɻɻʁ
T: EntityInterfaceΛ࣮ͯ͠Δ͕ɺTIdࢦఆ͞Εͨͷ
Slide 132
Slide 132 text
abstract class BaseRepository>
implements ArticleRepositoryInterface {
protected Map $collect = Map{};
public function add(T $article): void {
$this->collect->add(Pair{$article->getID(), $article});
}
// লུ
<<__Rx>>
public function findById(TId $id): T {
if($this->collect->contains($id)) {
return $this->collect->at($id);
}
throw new \RuntimeException('Not Found.');
}
}
ίϨΫγϣϯɺ ͷϚοϓʹ
Ұ؏ੑ͕͋Γɺ͜ΕҎ֎ͷͷར༻͞Εͳ͍
{
<<__Rx>>
public function isSatisfiedBy(T $entity): bool;
}
༷Λຬͨ͢ͷ͔Ͳ͏͔
Slide 140
Slide 140 text
༷ ࣮
*DDDࣗମͷΛ͢ΔΘ͚Ͱແ͍ͷͰৄࡉׂѪ
Slide 141
Slide 141 text
class LatestPostSpecification
implements SpecificationInterface> {
public function __construct(
private DateTime $since
) {}
<<__Rx>>
public function isSatisfiedBy(
Article $article
): bool {
return $article->createdAt() > $this->since;
}
}
͜Ε·Ͱͷྫͱಉ༷ʹ۩Ϋϥεʹ
࣮ࡍʹద༻ͤ͞ΔܕΛهड़
Slide 142
Slide 142 text
class LatestPostSpecification
implements SpecificationInterface> {
public function __construct(
private DateTime $since
) {}
<<__Rx>>
public function isSatisfiedBy(
Article $article
): bool {
return $article->createdAt() > $this->since;
}
}
ࢦఆ͞Εͨ࣌ΑΓ৽͍͠هࣄͳΒ
༷͕ຬͨ͞Ε·͢Α
Slide 143
Slide 143 text
<<__Rx>>
public function query(
SpecificationInterface $specification
): Map {
return $this->collect->filter(
$v ==> $specification->isSatisfiedBy($v)
);
}
༷ɾϦϙδτϦͱΈ߹ΘͤΔ
Slide 144
Slide 144 text
ΞϓϦέʔγϣϯαʔϏε
Slide 145
Slide 145 text
use type Vendor\Path\ArticleRepositoryInterface as Repository;
use type Vendor\Path\\ArticleSpecificationFactoryInterface as
SpecificationFactory;
final class LatestArticleFeed {
public function __construct(
private Repository> $repository,
private SpecificationFactory> $specification
) {
} ࢦఆͨ͠ܕΛར༻͢ΔΑ͏ʹద༻͞Εͨ
ΠϯλʔϑΣʔεΛ࣮ͨ͠ͷΛར༻͍ͯͩ͘͠͞
ܕએݴ͞ΕͨΠϯλʔϑΣʔεΛຬͨ͢
۩ΫϥεͷΠϯελϯε
$service = new Application\Service\LatestArticleFeed(
new Map\ArticleRepository(),
new Map\ArticleSpecificationFactory()
);
$result = $service->execute(
new Application\FeedRequestTransfer([
'datetime' => new DateTime('-4 hours'),
])
);
Slide 150
Slide 150 text
$service = new Application\Service\LatestArticleFeed(
new Map\ArticleRepository(),
new Map\ArticleSpecificationFactory()
);
$result = $service->execute(
new Application\FeedRequestTransfer([
'datetime' => new DateTime('-4 hours'),
])
);
ϑΥʔϜAPIͳͲ͔ΒΛૹ৴
Slide 151
Slide 151 text
final class FeedRequestTransfer {
const type FeedRequest = shape(
'datetime' => DateTime
);
public function __construct(
private array $request
) {}
public function getDateTime(): DateTime {
$request = $this->request as this::FeedRequest;
return $request['datetime'];
}
}
ҰൠతͳྻΛड͚औΔ
Slide 152
Slide 152 text
final class FeedRequestTransfer {
const type FeedRequest = shape(
'datetime' => DateTime
);
public function __construct(
private array $request
) {}
public function getDateTime(): DateTime {
$request = $this->request as this::FeedRequest;
return $request['datetime'];
}
}
ShapeͰྻʹରͯ͠
ظ͢ΔϑΟʔϧυͱܕఆٛ
Slide 153
Slide 153 text
final class FeedRequestTransfer {
const type FeedRequest = shape(
'datetime' => DateTime
);
public function __construct(
private array $request
) {}
public function getDateTime(): DateTime {
$request = $this->request as this::FeedRequest;
return $request['datetime'];
}
} ϑΟʔϧυͱܕݕࠪ
OKͳΒͦͷ··ྻ
NGͳΒType Error͕εϩʔ