Jdi na navigaci předmětu

Pokročilé techniky objektově orientovaného programování

Klonování

  • proměnná s instancí se chová jako reference: přiřazení ani předání do funkce kopii nevytvoří
  • někdy je vhodné předat kopii (třeba při kešování)
  • k tomu slouží operátor clone
    • vytváří mělkou kopii: atributy obsahující další objekty zůstávají sdílené
    • hlubokou kopii zajistí magická metoda __clone, která se zavolá na nové kopii
    • od PHP 8.5 lze použít i jako funkci a vybrané atributy na kopii rovnou přenastavit
  • viz referenční dokumentace

Příklad - mělká a hluboká kopie

class Order {
  public function __construct(
    public string $name,
    public DateTime $created,
  ) {}
}

$order = new Order( 'Objednávka', new DateTime( '2026-01-01' ) );
$copy = clone $order;

$copy->name = 'Kopie';
echo $order->name; // Objednávka - řetězec se zkopíroval

$copy->created->modify( '+1 day' );
echo $order->created->format( 'Y-m-d' ); // 2026-01-02 - DateTime je sdílený (NEŽÁDOUCÍ)

Hlubokou kopii zajistí __clone:

class Order {
  // ...
  public function __clone() {
    $this->created = clone $this->created;
  }
}

Od PHP 8.5 lze při klonování rovnou změnit vybrané atributy (funguje i pro readonly):

$copy = clone( $order, [ 'name' => 'Kopie' ] );

Dědičnost - self, late static binding

Pozor na jakou třídu ukazuje self a static.

class ParentClass {
    public function hello():void {
        echo "Hello from parent class" . PHP_EOL;
    }

    public function callSelf(): void {
        self::hello();
    }

    public function callStatic(): void {
        static::hello();
    }
}

class ChildClass extends ParentClass {
    public function hello():void {
        echo "Hello from child class" . PHP_EOL;
    }
}

$parent = new ParentClass();
$parent->callSelf();
$parent->callStatic();

$child = new ChildClass();
$child->callSelf();
$child->callStatic();

Platí:

self

  • v čase čtení kódu (compile time)

static

  • v čase běhu kódu (runtime)

Příklad

class Attachment {
  public const string TYPE = 'application/octet-stream';
  protected static int $sequence = 0;
  public function __construct()
    {
        $this->id = ++self::$sequence;
        $this->type = static::TYPE;
    }
}

class Text extends Attachment
{
    public const string TYPE = 'text/plain';
}

class JpegImage extends Attachment
{
    public const string TYPE = 'image/jpeg';
}

Abstraktní třídy

  • klíčové slovo abstract
  • sdílení kódu
  • nelze instanciovat
  • v potomcích abstraktní třídy obvykle různé implementace operací
  • třída s alespoň jednou abstraktní metodou musí být sama abstraktní
  • může obsahovat i atributy

Příklad

abstract class Image {
  abstract function display();
}

class Jpeg extends Image {
  function display() { ... }
}

Rozhraní

Příklad

interface Filesystem {
  function mkdir($path);
  function rmdir($path);
}

class LocalFilesystem implements Filesystem {
  function mkdir($path) { ... }
  function rmdir($path) { ... }
}

Traity

  • klíčové slovo trait, použití use uvnitř třídy
  • náhrada za vícenásobnou dědičnost
  • kdekoliv znovupoužitelný kód
  • přidává kód i do spolu nesouvisejících tříd
  • může pracovat s $this cílové třídy

Příklad

trait CRUD {
  public function create(...) {...}
}

class Entity {
  use CRUD;
}