Oop php rozdíl mezi statickými metodami a dynamickými. Pozdní statické linkování v PHP. Úskalí statických proměnných

Reg.ru: domény a hosting

Největší registrátor a poskytovatel hostingu v Rusku.

V provozu je více než 2 miliony doménových jmen.

Propagace, doménová pošta, obchodní řešení.

Již si vybralo více než 700 tisíc zákazníků po celém světě.

*Najetím myší pozastavíte rolování.

Zpět Vpřed

Statické metody a vlastnosti v PHP

V předchozích materiálech jsme si osvojili základní možnosti objektově orientovaného programování v PHP a nyní přecházíme ke studiu složitějších a zajímavějších aspektů.

Předtím jsme vždy pracovali s předměty. Třídy jsme popsali jako šablony, které vytvářejí objekty, a objekty jako aktivní komponenty, jejichž metody voláme a k jejichž vlastnostem přistupujeme.

To vedlo k závěru, že v objektově orientovaném programování se skutečná práce provádí pomocí instancí tříd. A třídy jsou nakonec jen šablony pro vytváření objektů.

Jenže ve skutečnosti to tak jednoduché není. K metodám i vlastnostem můžeme přistupovat spíše v kontextu třídy než objektu. Takové metody a vlastnosti se nazývají „statické“ a musí být deklarovány pomocí klíčového slova statický.

Třída StaticExample ( statická veřejná $aNum = 0; statická veřejná funkce sayHello() ( tisk "Ahoj!"; ) )

Statické metody jsou funkce používané v kontextu třídy. Oni sami nemají přístup k žádným běžným vlastnostem třídy, protože takové vlastnosti patří objektům.

Avšak mezi statickými metodami, jak jste již pravděpodobně uhodli, můžete přistupovat ke statickým vlastnostem. A pokud změníte statickou vlastnost, všechny instance této třídy budou mít přístup k nové hodnotě.

Vzhledem k tomu, že ke statickému prvku se přistupuje prostřednictvím třídy a nikoli prostřednictvím instance objektu, nepotřebujeme proměnnou, která odkazuje na objekt. Místo toho se použije název třídy následovaný dvěma dvojtečkami "::".

Tisk statického příkladu::$aNum; StatickýPříklad::sayHello();

Tuto syntaxi byste již měli znát od základů OOP v PHP. Použili jsme konstrukci "::" v kombinaci s klíčovým slovem rodič za účelem přístupu k přepsané metodě nadřazené třídy.

Nyní, stejně jako tehdy, odkazujeme na třídu, nikoli na data obsažená v objektu. Klíčové slovo můžete použít v kódu třídy rodič za účelem přístupu k nadtřídě bez použití názvu třídy.

Pro přístup ke statické metodě nebo vlastnosti ze stejné třídy (a ne z podřízené třídy) použijeme klíčové slovo .

Klíčové slovo se používá pro přístup k aktuální třídě a pseudo proměnné $toto- k aktuálnímu objektu. Proto mimo třídu Statický příklad vstoupíme do nemovitosti $aNum pomocí názvu třídy.

StatickýPříklad::$aNum;

A uvnitř třídy Statický příklad můžete použít klíčové slovo .

Třída StaticExample ( statická veřejná $aNum = 0; statická veřejná funkce sayHello() ( self::$aNum++; tisk "Ahoj! (" . self::$aNum . ")\n"; ) )

Poznámka: kromě případů, kdy přistupujete k přepsané metodě nadřazené třídy, by měl být konstrukt "::" vždy používán pouze pro přístup ke statickým metodám nebo vlastnostem.

Podle definice nejsou statické metody volány v kontextu objektu. Z tohoto důvodu se statické metody a vlastnosti často nazývají proměnné třídy a vlastnosti. V důsledku toho nemůžete použít pseudo proměnnou $toto uvnitř statické metody.

Proč vůbec používat statickou metodu nebo vlastnost?

Nyní jsme se dostali k nejdůležitější otázce. Faktem je, že statické prvky mají řadu užitečných vlastností.

Za prvé, jsou přístupné odkudkoli ve skriptu (za předpokladu, že máte přístup ke třídě). To znamená, že můžete přistupovat k funkcím, aniž byste předávali instanci třídy z jednoho objektu do druhého, nebo v horším případě ukládali instanci objektu do globální proměnné.

Za druhé, statická vlastnost je dostupná pro každou instanci objektu této třídy. Můžete tedy definovat hodnoty, které by měly být dostupné všem objektům daného typu.

A konečně za třetí, samotný fakt, že nepotřebujete mít instanci třídy pro přístup k její statické vlastnosti nebo metodě, zabrání vytváření instancí objektů pouze kvůli volání jednoduché funkce.

Abychom to demonstrovali, vytvořte pro třídu statickou metodu NakupovatProdukt který automaticky vytvoří instanci objektů NakupovatProdukt. Pojďme definovat tabulku pomocí SQLite produkty následovně:

CREATE TABLE produkty (ID INTEGER PRIMARY KEY AUTOINCREMENT, typ TEXT, TEXT křestního jména, TEXT hlavního jména, TEXT názvu, plovoucí cena, numpages int, playlength int, sleva int)

Nyní vytvoříme metodu getInstance(), kterému je předán řetězcový identifikátor a objekt typu PDO. Budou použity k extrahování řádku z databázové tabulky, na základě kterého je objekt typu NakupovatProdukt, se vrátil do volajícího programu.

Tyto metody můžeme přidat do třídy NakupovatProdukt, který pro nás vznikl v dřívějších materiálech. Jak asi víte, PDO znamená PHP Data Object. Třída PDO poskytuje obecné rozhraní pro různé databázové aplikace.

// Třída ShopProduct private $id = 0; veřejná funkce setID($id) ( $this->id = $id; ) // ... veřejná statická funkce getInstance($id, PDO $pdo) ( $stmt = $pdo->prepare("vybrat * z produktů) kde id=?"); $result = $stmt->execute(array($id)); $row = $stmt->fetch(); if (empty($row)) ( return null; ) if ($ row["type"] == "kniha") ( $product = new BookProduct($row["title"], $row["firstname"], $row["mainname"], $row["price"] , $row["numpages"] ) else if ($row["type"] == "cd") ( $product = new CdProduct($row["title"], $row["firstname"], $row ["mainname"], $row["price"], $row["playlength"] ) else ( $product = new ShopProduct($row["title"], $row["firstname"], $row[" mainname"], $row["price"]); $product->setId($row["id"]); $product->setDiscount($row["sleva"]); produkt; ) // .. .

Jak vidíte, metoda getInstance() vrací objekt typu NakupovatProdukt a je dostatečně „chytrý“ na základě hodnoty pole typ vytvořit objekt s požadovanými vlastnostmi.

Konkrétně jsem vynechal kód pro zpracování chyb, aby byl příklad co nejstručnější. Například v reálné verzi tohoto kódu nemůžeme být příliš důvěřiví a předpokládat, že předaný objekt PDO byl správně inicializován a připojen k požadované databázi.

Ve skutečnosti bychom pravděpodobně měli zabalit objekt PDO do třídy, která toto chování zaručuje. K tomuto problému se vrátíme v některém z našich budoucích materiálů.

Metoda getInstance() užitečnější v kontextu třídy než v kontextu objektu. Umožňuje nám snadno převádět data umístěná v databázi na objekt, a k tomu nepotřebujeme mít samostatnou instanci objektu typu NakupovatProdukt.

Tato metoda nepoužívá žádné metody nebo vlastnosti, které vyžadují samostatnou instanci objektu, takže není důvod ji nedeklarovat jako statickou. Poté, když máme správný objekt PDO, můžeme tuto metodu volat odkudkoli v aplikaci.

$dsn = "sqlite://home/bob/projects/products.db"; $pdo = nové PDO($dsn, null, null); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $obj = ShopProduct::getInstance(1, $pdo);

Takové metody fungují jako „továrny“ v tom, že berou „surové“ materiály (například data získaná z databázového řetězce nebo konfiguračního souboru) a používají je k vytváření objektů.

Termín "továrna" odkazuje na kód používaný k vytváření instancí objektů. Později se s vámi setkáme s příklady takových „továren“.


Trvalé vlastnosti

Některé vlastnosti by se neměly měnit. Například prvky jako chybové kódy nebo stavové kódy programu jsou obvykle specifikovány ručně ve třídách. Přestože by měly být veřejné a statické, klientský kód by je neměl mít možnost změnit.

Chcete-li to provést, můžete definovat trvalé vlastnosti v rámci třídy. Stejně jako globální konstanty nelze konstanty třídy po jejich definování změnit. Trvalá vlastnost je deklarována pomocí klíčového slova konst.

Na rozdíl od běžných vlastností před trvalým názvem vlastnosti není znak dolaru. Podle konvence jsou jim často dávána jména, která obsahují pouze velká písmena, jako v následujícím příkladu:

Třída ShopProduct ( const AVAILABLE = 0; const OUT_OF_STOCK = 1; // ...

Trvalé vlastnosti mohou obsahovat pouze hodnoty, které jsou specifické pro primitivní typ. Konstantě nelze přiřadit objekt.

Stejně jako statické vlastnosti jsou trvalé vlastnosti přístupné prostřednictvím třídy spíše než prostřednictvím instance objektu. Stejně jako je konstanta definována bez znaku dolaru, nevyžaduje při přístupu k ní žádný úvodní symbol.

Print ShopProdukt::DOSTUPNÉ;

Pokus o přiřazení hodnoty konstantě poté, co byla deklarována, bude mít za následek chybu během fáze analýzy.

Konstanty by se měly používat, když vlastnost musí být přístupná všem instancím třídy a když hodnota vlastnosti musí být pevná a neměnná.

Tím tento článek končí a v příštím si o něm povíme.

Líbil se vám materiál a chcete mi poděkovat?
Stačí sdílet se svými přáteli a kolegy!


Velmi důležitou vlastností OOP je přítomnost statických vlastností a metod. Hlavní věc je, že musíte okamžitě pochopit, že takové vlastnosti a metody nepatří do objektu, ale do třídy. To je potřeba pochopit hned od začátku, ale na využití statických vlastností a metod v PHP se podívám v tomto článku.

Nejklasičtějším příkladem je třída zodpovědná za matematické funkce. Pokud někdo zná Javu, tak ví, že existuje třída Math (takovou třídu má i JavaScript), obsahující mnoho matematických funkcí. A tam jsou metody statické. To znamená, že abyste mohli vypočítat jakýkoli sinus nebo exponent, nemusíte vytvářet objekt této třídy, což je velmi pohodlné.

Pojďme napsat menší kopii této třídy, ale pouze pro PHP:

V tomto kódu jsem ukázal použití statických metod a vlastností. Vezměte prosím na vědomí, že jsem implementoval klasickou metodu počítadla objektů. Stalo se to pouze proto, že pole počet je statické a má stejnou hodnotu pro všechny objekty.

Dalším oblíbeným příkladem použití statických metod a vlastností je protokolování. Všechny položky jsou přidávány prostřednictvím statických metod. Je také velmi běžné vytvořit třídu skládající se z mnoha nastavení a také tam jsou všechna pole statická. Jak vidíte, příkladů použití statických metod a vlastností v PHP a dalších jazycích je více než dost, takže je nutné umět s nimi pracovat.

Late Static Binding (LSB) je poslední tři roky žhavým tématem diskuzí ve vývojářských kruzích PHP (a konečně jsme se k němu dostali v PHP 5.3). Ale proč je to potřeba? V tomto článku se podíváme, jak přesně pozdní statická vazba může značně zjednodušit váš kód.

Na schůzce vývojářů PHP, která se konala v Paříži v listopadu 2005, bylo téma pozdního statického linkování formálně projednáno hlavním vývojovým týmem. Souhlasili s jeho implementací, spolu s mnoha dalšími tématy, která byla na programu. Podrobnosti měly být dohodnuty v rámci otevřených diskusí.

Od pozdní statická vazba byl oznámen jako nadcházející funkce, uplynuly dva roky. A konečně se LSB stalo dostupným pro použití v PHP 5.3. Tato událost ale zůstala bez povšimnutí vývojářů používajících PHP, z poznámek pouze stránka v manuálu.

Stručně řečeno, nová funkce pozdních statických vazeb umožňuje objektům stále dědit metody z nadřazených tříd, ale navíc umožňuje zděděným metodám mít přístup ke statickým konstantám, metodám a vlastnostem podřízené třídy, nejen k rodičovské třídě. Podívejme se na příklad:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

třídní pivo (
const NAME = "Pivo!" ;

return self :: JMÉNO ;
}
}
třída Ale rozšiřuje pivo (
const NAME = "Ale!" ;
}

$beerDrink = nové Pivo;
$aleDrink = nový Ale;

echo "Pivo je: ".
$beerDrink -> getName() . "\n" ;

echo "Ale je: ".

$aleDrink -> getName() . "\n" ;

Tento kód vytvoří následující výsledek:

Pivo je: Pivo!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

třídní pivo (
const NAME = "Pivo!" ;
Ale je: Pivo!
return self :: JMÉNO ;
}
Třída Ale dědí metodu getName(), ale self stále ukazuje na třídu, ve které je použita (v tomto případě třída Beer). To zůstalo v PHP 5.3, ale bylo přidáno slovo static. Podívejme se znovu na příklad:
veřejná funkce getName() (
}
}

třída Ale rozšiřuje pivo (
const NAME = "Ale!" ;
}

$beerDrink = nové Pivo;

$aleDrink = nový Ale;

echo "Pivo je: ".
$beerDrink -> getName() . "\n" ;

veřejná funkce getStaticName() (
return static::NAME ;

echo "Pivo je vlastně: " .

$beerDrink -> getStaticName () . "\n" ;

echo "Ale je ve skutečnosti: ".

  • $aleDrink -> getStaticName() . "\n" ;

Nové klíčové slovo static určuje, že by se měla použít konstanta zděděné třídy místo konstanty, která byla definována ve třídě, kde je deklarována metoda getStaticName(). Slovo static bylo přidáno pro implementaci nové funkce a pro zpětnou kompatibilitu funguje self stejně jako v předchozích verzích PHP.

Interně je hlavním rozdílem (a ve skutečnosti důvodem, proč se vazba nazývá pozdní) mezi těmito dvěma přístupovými metodami, že PHP určí hodnotu pro self::NAME v době „kompilace“ (když jsou znaky PHP převedeny na strojový kód který bude zpracován Zend engine) a pro static::NAME bude hodnota určena při spuštění (v okamžiku, kdy je strojový kód spuštěn v Zend engine).

Toto je další nástroj pro vývojáře PHP. V druhé části se podíváme na to, jak se dá využít k dobru.

Konzultace

V PHP jsou proměnné lokální. To znamená, že proměnná definovaná a zadaná ve funkci (metodě) existuje pouze během provádění této funkce (metody). Při ukončení metody je lokální proměnná zničena a při opětovném vstupu je vytvořena znovu. Ve výše uvedeném kódu je takovou lokální proměnnou proměnná $a – existuje pouze uvnitř funkce foo() a je vytvořena znovu při každém volání této funkce. Zvyšování proměnné v tomto kódu nemá smysl, protože hned na dalším řádku kódu funkce dokončí svou práci a hodnota proměnné se ztratí. Bez ohledu na to, kolikrát voláme funkci foo(), vždy vypíše 0...

Vše se však změní, pokud před zadáním vložíme klíčové slovo static:

Funkce foo() ( static $a = 0; echo $a; $a = $a + 1; ) foo(); // 0 foo(); // 1 foo(); // 2

Statické klíčové slovo zapsané před přiřazením hodnoty k lokální proměnné má následující účinky:

  • Přiřazení se provede pouze jednou, při prvním volání funkce
  • Hodnota takto označené proměnné se po skončení funkce uloží.
  • Při následných voláních funkce namísto přiřazení proměnná obdrží dříve uloženou hodnotu
  • Toto použití slova static se nazývá statická lokální proměnná Úskalí statických proměnných Samozřejmě, jako vždy v PHP, existují určitá úskalí.

    Prvním kamenem je, že ke statické proměnné lze přiřadit pouze konstanty nebo konstantní výrazy.
    Zde je kód:
    static $a = bar();

    nevyhnutelně povede k chybě analyzátoru. Naštěstí od verze 5.6 je možné přiřadit nejen konstanty, ale také konstantní výrazy (například „1+2“ nebo „“), tedy výrazy, které nezávisí na jiném kódu a lze je vypočítat. ve fázi kompilace
    Druhým kamenem je, že metody existují v jediné kopii.
    Zde je vše trochu složitější. Abyste pochopili podstatu, zde je kód:
    třída A ( public function foo() ( static $x = 0; echo ++$x; ) ) $a1 = new A; $a2 = nové A; $a1->foo(); // 1 $a2->foo(); // 2 $a1->foo(); // 3 $a2->foo(); // 4

    Toto chování může být neočekávané pro vývojáře, který na to není připraven a může být zdrojem chyb. Je třeba poznamenat, že dědičnost třídy (a metody) vede k vytvoření nové metody:

    Třída A ( public function foo() ( static $x = 0; echo ++$x; ) ) třída B rozšiřuje A ( ) $a1 = new A; $b1 = nové B; $a1->foo(); // 1 $b1->foo(); // 1 $a1->foo(); // 2 $b1->foo(); // 2

    Závěr: Dynamické metody v PHP existují v kontextu tříd, nikoli objektů. A pouze za běhu dochází k substituci „$this = aktuální_objekt“.

    Druhým významem jsou statické vlastnosti a metody tříd V objektovém modelu PHP je možné nastavit vlastnosti a metody nejen pro objekty - instance třídy, ale i pro třídu jako celek. K tomu se také používá klíčové slovo static:

    Třída A ( public static $x = "foo"; public static function test() ( return 42; ) ) echo A::$x; // "foo" echo A::test(); // 42
    Pro přístup k těmto vlastnostem a metodám se používají konstrukce s dvojitou dvojtečkou („Paamayim Nekudotayim“), jako je CLASS_NAME::$Variablename a CLASS_NAME::Methodname().

    Je samozřejmé, že statické vlastnosti a statické metody mají své vlastní charakteristiky a úskalí, která musíte znát.

    První funkce je banální – neexistuje žádné $this.

    Ve skutečnosti to vyplývá ze samotné definice statické metody - protože je spojena s třídou, nikoli s objektem, není k dispozici pseudoproměnná $this, která ukazuje na aktuální objekt v dynamických metodách. Což je zcela logické.

    Musíte však vědět, že na rozdíl od jiných jazyků PHP nedetekuje situaci „$toto je napsáno statickou metodou“ ve fázi analýzy nebo kompilace. K takové chybě může dojít pouze za běhu, pokud se pokusíte spustit kód s $this uvnitř statické metody.
    Kód takto:
    třída A ( public $id = 42; statická veřejná funkce foo() ( echo $this->id; ) )
    nezpůsobí žádné chyby, pokud se nepokusíte použít metodu foo() nevhodně:

    $a = nové A; $a->foo();
    (a okamžitě dostanete „Závažná chyba: Použití $this, když není v kontextu objektu“)
    Druhým rysem je, že statika není axiom!

    třída A ( statická veřejná funkce foo() ( echo 42; ) ) $a = new A; $a->foo();
    To je ono, ano. Statická metoda, pokud v kódu neobsahuje $this, může být volána v dynamickém kontextu, jako je objektová metoda. Toto není chyba v PHP.
    Dynamickou metodu, která nepoužívá $this, lze spustit ve statickém kontextu. Obdržíte však varování „Nestatická metoda A::foo() by neměla být volána staticky“ na úrovni E_STRICT. Je na vás, abyste se rozhodli, zda budete striktně dodržovat kódové standardy, nebo varování potlačíte. První je samozřejmě výhodnější.

    A mimochodem, vše napsané výše platí pouze pro metody. Použití statické vlastnosti přes "->" je nemožné a vede k fatální chybě.

    Třetí význam, který se zdá být nejsložitější - pozdní statická vazba Vývojáři jazyka PHP se nezastavili u dvou významů klíčového slova „static“ a ve verzi 5.3 přidali další „vlastnost“ jazyka, která je implementována stejným slovem! Říká se tomu "late static binding" nebo LSB (Late Static Binding).

    Nejjednodušší způsob, jak pochopit podstatu LSB, jsou jednoduché příklady:

    Model třídy ( public static $table = "table"; veřejná statická funkce getTable() ( return self::$table; ) ) echo Model::getTable(); // "tabulka"
    Klíčové slovo self v PHP vždy znamená „název třídy, kde je toto slovo napsáno“. V tomto případě je self nahrazeno třídou Model a self::$table za Model::$table.
    Tato jazyková funkce se nazývá „časná statická vazba“. Proč brzy? Protože vazba self a konkrétního názvu třídy nenastává za běhu, ale v dřívějších fázích – parsování a kompilaci kódu. No, „statické“ - protože mluvíme o statických vlastnostech a metodách.

    Pojďme trochu změnit náš kód:

    Model třídy ( public static $table = "table"; veřejná statická funkce getTable() ( return self::$table; ) ) class User extends Model ( public static $table = "users"; ) echo User::getTable() ; // "tabulka"

    Nyní chápete, proč se PHP v této situaci chová neintuitivně. self byl přidružen ke třídě Model, když nebylo nic známo o třídě User, a proto ukazuje na Model.

    co mám dělat?

    K vyřešení tohoto dilematu byl ve fázi běhu vynalezen „pozdní“ mechanismus vazby. Funguje to velmi jednoduše – stačí napsat „statický“ místo slova „self“ a spojení se naváže s třídou, která tento kód volá, a ne s tou, kde je napsán:
    class Model ( public static $table = "table"; veřejná statická funkce getTable() ( return static::$table; ) ) class User extends Model ( public static $table = "users"; ) echo User::getTable() ; // "uživatelé"

    Toto je záhadná „pozdní statická vazba“.

    Je třeba poznamenat, že pro větší pohodlí je v PHP kromě slova „static“ také speciální funkce get_known_class(), která vám řekne, v jaké třídě váš kód aktuálně funguje.

    Šťastné rozhovory!



    
    Nahoru