Objektově orientované programování
Základní principy a pojmy
- zapouzdření - těsný vztah mezi daty a operacemi
- dědičnost - sdílení stejných vlastností
- polymorfismus - různá implementace v potomcích stejného rodiče
Základní principy a pojmy
- třída - definuje formát dat a operace
- objekt (instance) - realizace třídy, konkrétní hodnoty atributů
V některých jazycích je i třída objektem.
OOP v PHP
- třídní OOP (narozdíl od prototypové v plain JS)
- viditelnost -
private
,protected
,public
abstract
afinal
třídy a metody- magické metody
- rozhraní, traity
- klonování
- type hinting
Definice třídy
klíčové slovo
class
class Account { protected $number; protected $amount; protected $transactions = []; public function addTransaction($transaction) { ... } public function getTransactions() { ... } ... }
Instanciace, přiřazení
- instanciace pomocí operátoru
new
- přiřazení referencí
- kopírování explicitně pomocí operátoru
clone
$account = new Account; // pokud se konstruktoru nepředávají argumenty nemusí být ()
$card = new Card(12345);
$skim = clone $card;
Třída vs instance
- instance
- instanční atributy - zvlášť pro každou instanci
- metody
- třída
- třídní atributy - sdílené pro všechny instance (
static
) - metody - nemohou pracovat s instancí
- konstanty
- třídní atributy - sdílené pro všechny instance (
Odkazování na třídu a instanci
- instance
- názvem proměnné (proměnná = reference) - zvenku
- speciální proměnná
$this
- zevnitř, reprezentuje volající instanci
- třída
- pomocí názvu třídy - zvenku i zevnitř
- zevnitř pomocí
self
nebostatic
Přistupování k atributům a metodám
- object operator
->
- scope resolution operator
::
(Paamayim Nekudotayim)
Přistupování k atributům a metodám
class Card
{
...
function getPin() {
return substr($this->number,0,4); // zevnitř $this->...
}
}
$number = $card->getNumber(); // zvenku $promenna->...
Přistupování k atributům a metodám
class Card
{
public static function issue() {
return new self; // vrátí vlastní instanci
}
}
$newCard = Card::issue(); // zvenku třída::...
Viditelnost
private
- přístup pouze zevnitř třídyprotected
- přístup z třídy a jejích potomkůpublic
(výchozí) - bez omezení
Měnitelnost
readonly
- do atributu lze zapsat jen v rámci kontruktoru
Instanční atributy
object operator
->
class Account { public $number; } // obvyklé použití, před number není $ echo $account->number; // proměnná proměnná $property = 'number'; echo $account->$property;
Třídní atributy
- modifikátor
static
- přístup pomocí scope resolution operator
::
class Bank {
static $accounts;
}
// z venku
Bank::$accounts
// zevnitř
self::$accounts
// zevnitř - late static binding
static::$accounts
Konstanty
class Card {
const TYPE_VISA = 1;
const TYPE_MASTERCARD = 2;
const DEFAULT_HELLO = "Ahojky!!!";
}
echo Card::TYPE_VISA;
- od PHP 8.3 mohou být typovány
class Card {
const int TYPE_VISA = 1;
const int TYPE_MASTERCARD = 2;
const string DEFAULT_HELLO = "Ahojky!!!";
}
echo Card::TYPE_VISA;
Instanční a třídní metody
- platí totéž, co u atributů
class Card {
public function getNumber() {
return $this->number;
}
public static function getTypes() {
return [
self::TYPE_VISA, self::TYPE_MASTERCARD
];
}
}
Konstruktor
- inicializace objektu, nepovinná
magická metoda
__construct
class Order { protected static int $sequence = 0; protected int $id; protected string $name; public function __construct(string $name) { $this->id = ++static::$sequence; $this->name = $name; } }
Od php 8.0 může být atribut deklarován v konstruktoru (pomocí slov
private
,protected
nebopublic
)class Order { protected static int $sequence = 0; protected int $id; public function __construct(protected string $name) { $this->id = ++static::$sequence; } }
Destruktor
- uvolnění objektu (deinicializace), používá se zřídka
- magická metoda
__destruct
- volán garbage collectorem
- bez argumentů
Dědičnost
- vztah mezi třídami
- specializace (rodič → potomek)
- generalizace (potomek → rodič)
Dědičnost
class Card {
protected $number;
}
class DebitCard extends Card {
protected $limit;
}
class CreditCard extends Card {
protected $dueDay;
}
Dědičnost - přístup k rodiči
explicitně: klíčové slovo
parent
a scope resolution operatorparent::$number // přístup k atributu parent::lock() // přístup k metodě
pokud není atribut nebo metoda překryta v potomkovi, může přistupovat i přes potomka
$child->number // přístup k atributu $child->lock() // přístup k metodě
Dědičnost - konstruktor
- obvykle voláme rodičovský konstruktor na začátku konstruktoru potomka
pokud není v potomkovi implementovaný, volá se rodičovský automaticky
function __construct() { parent::__construct(); // lze předat argumenty $this->dueDay = 20; }
Dědičnost - destruktor
obvykle voláme na konci, po provedení operací pro potomka
function __destruct() { // uvolnění dat potomka apod. parent::__destruct(); }
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();
Užitečné třídy přímo v PHP
Autoloading
- pokud třída není definovaná (známá) provádí se autoloading
- lze nadefinovat funkci, která načtení třídy zařídí a program může běžet dál
- úspora paměti, výkonu - načítá se jen to, co je potřeba
Autoloading
- magická funkce
__autoload
(deprecated od 7.2, smazáno od 8.0) spl_autoload_register