3v4l.org

run code in 300+ PHP versions simultaneously
<?php interface ProductRepository { public function findReferenceBySku(string $sku): Product; public function findIdBySku(string $sku): int; } class Product { public function __construct( public int $id, ) { } } class ProductDatabaseRepository implements ProductRepository { public function findReferenceBySku(string $sku): Product { $id = $this->findIdBySku($sku); return $this->getProductReference($id); } private function getProductReference(int $id) { // check entity manager for existing object // and generate proxy if not found return new Product($id); } public function findIdBySku(string $sku): int { $this->queryDatabase(); return match($sku) { 'sku1' => 1, }; } protected function queryDatabase() { // note this method is not public var_dump('query database'); } } class ProductCachedRepository implements ProductRepository { private array $cachedIds = []; public function __construct( private ProductRepository $inner ) {} public function findReferenceBySku(string $sku): Product { // not able to delegate this logic directly to inner class // (loss of findIdBySku() overridden logic) //return $this->inner->findReferenceBySku($sku); // as well not able call decorated method with substitude this return $this->inner->findReferenceBySku(...)->call($this, $sku); } public function findIdBySku(string $sku): int { var_dump('check cache'); return $this->cachedIds[$sku] ??= $this->inner->findIdBySku($sku); } public function __call($name, $arguments) { // all not public methods of inner repository // which are not declared in current class // are delegated to inner repository return (fn() => $this->$name(...$arguments)) ->call($this->inner); } } $repository = (new ProductCachedRepository(new ProductDatabaseRepository())); var_dump('call1', $repository->findReferenceBySku('sku1')); var_dump('call2', $repository->findReferenceBySku('sku1')); // cache hit expected var_dump('call2', $repository->findReferenceBySku('sku1')); // cache hit expected

preferences:
25.21 ms | 404 KiB | 5 Q