Myöhäinen staattinen sidonta. Staattiset luokan jäsenet. Älä anna heidän pilata koodiasi Epäitsekäs staattinen php p

Ei ole mikään salaisuus, että ihmiset haluavat haastattelujen aikana esittää hankalia kysymyksiä. Ei aina riittävä, ei aina liity todellisuuteen, mutta tosiasia pysyy tosiasiana - he kysyvät. Kysymys on tietysti erilainen, ja joskus ensisilmäyksellä tyhmältä vaikuttava kysymys on itse asiassa tarkoitettu testaamaan, kuinka hyvin osaat kieltä, jolla kirjoitat.

Yritetään purkaa yksi näistä kysymyksistä "pala palalta" - Mitä sana "staattinen" tarkoittaa PHP:ssä ja miksi sitä käytetään?

Staattisella avainsanalla on kolme eri merkitystä PHP:ssä. Katsotaanpa niitä kronologisessa järjestyksessä sellaisina kuin ne esiintyivät kielessä.

Ensimmäinen arvo on staattinen paikallinen muuttuja

funktio foo() ( $a = 0; kaiku $a; $a = $a + 1; ) foo(); // 0 foo(); // 0 foo(); // 0

PHP:ssä muuttujat ovat paikallisia. Tämä tarkoittaa, että muuttuja, joka on määritelty ja jolle on annettu arvo funktiossa (menetelmässä), on olemassa vain kyseisen funktion (menetelmän) suorituksen aikana. Kun menetelmä poistuu, paikallinen muuttuja tuhoutuu, ja kun se tulee uudelleen, se luodaan uudelleen. Yllä olevassa koodissa tällainen paikallinen muuttuja on $a -muuttuja - se on olemassa vain foo()-funktion sisällä ja luodaan uudelleen joka kerta, kun tätä funktiota kutsutaan. Muuttujan lisääminen tässä koodissa on merkityksetöntä, koska heti seuraavalla koodirivillä funktio lopettaa työnsä ja muuttujan arvo menetetään. Riippumatta siitä, kuinka monta kertaa kutsumme foo()-funktiota, se tulostaa aina 0...

Kaikki kuitenkin muuttuu, jos laitamme staattisen avainsanan ennen tehtävää:

Funktio foo() (staattinen $a = 0; kaiku $a; $a = $a + 1; ) foo(); // 0 foo(); // 1 foo(); // 2

Staattisella avainsanalla, joka on kirjoitettu ennen arvon määrittämistä paikalliselle muuttujalle, on seuraavat vaikutukset:

  1. Tehtävä suoritetaan vain kerran, ensimmäisellä toiminnon kutsulla
  2. Tällä tavalla merkityn muuttujan arvo tallennetaan funktion päätyttyä.
  3. Myöhemmissä funktion kutsuissa muuttuja saa osoituksen sijaan aiemmin tallennetun arvon
Tätä sanan staattista käyttöä kutsutaan staattinen paikallinen muuttuja.
Staattisten muuttujien sudenkuopat
Tietysti, kuten aina PHP:ssä, on joitain sudenkuoppia.

Ensimmäinen kivi on, että staattiseen muuttujaan voidaan määrittää vain vakioita tai vakiolausekkeita. Tässä on koodi:
staattinen $a = bar();
johtaa väistämättä jäsennysvirheeseen. Onneksi versiosta 5.6 alkaen on tullut mahdolliseksi määrittää vakioiden lisäksi vakiolausekkeita (esim. “1+2” tai “”), eli lausekkeita, jotka eivät riipu muusta koodista ja jotka voidaan laskea kokoamisvaiheessa

Toinen kivi on se, että menetelmät ovat olemassa yhdessä kopiossa.
Tässä kaikki on hieman monimutkaisempaa. Ymmärtääksesi olemuksen, tässä on koodi:
luokka A ( julkinen funktio foo() ( staattinen $x = 0; kaiku ++$x; ) ) $a1 = uusi A; $a2 = uusi A; $a1->foo(); // 1 $a2->foo(); // 2 $a1->foo(); // 3 $a2->foo(); // 4
Vastoin intuitiivista odotusta "eri kohteet - erilaisia ​​menetelmiä"Näemme tässä esimerkissä selvästi, että PHP:n dynaamiset menetelmät "eivät kerro." Vaikka meillä olisi sata tämän luokan objektia, menetelmä on olemassa vain yhdessä tapauksessa; se on vain, että siihen heitetään eri $this jokaisen kutsun yhteydessä.

Tämä käyttäytyminen voi olla odottamatonta kehittäjälle, joka ei ole siihen valmistautunut, ja se voi olla virheiden lähde. On huomattava, että luokan (ja menetelmän) periytyminen johtaa uuden menetelmän luomiseen:

Luokka A ( julkinen funktio foo() ( staattinen $x = 0; kaiku ++$x; ) ) luokka B laajentaa A ( ) $a1 = uusi A; $b1 = uusi B; $a1->foo(); // 1 $b1->foo(); // 1 $a1->foo(); // 2 $b1->foo(); // 2

Johtopäätös: Dynaamiset menetelmät PHP:ssä ovat luokkien, ei objektien, yhteydessä. Ja vain ajon aikana tapahtuu korvaus "$this = current_object".

Toinen merkitys on luokkien staattiset ominaisuudet ja menetelmät

PHP-oliomallissa on mahdollista asettaa ominaisuuksia ja menetelmiä paitsi objekteille - luokan ilmentymille, myös koko luokalle. Staattista avainsanaa käytetään myös tähän:

Luokka A ( julkinen staattinen $x = "foo"; julkinen staattinen funktiotesti() ( paluu 42; ) ) echo A::$x; // "foo" echo A::test(); // 42
Tällaisten ominaisuuksien ja menetelmien käyttämiseen käytetään kaksoispisteen ("Paamayim Nekudotayim") konstrukteja, kuten CLASS_NAME::$Variablename ja CLASS_NAME::Methodname().

On sanomattakin selvää, että staattisilla ominaisuuksilla ja staattisilla menetelmillä on omat ominaisuutensa ja " vedenalaisia ​​kiviä"joka sinun täytyy tietää.

Ensimmäinen ominaisuus on banaali - tätä ei ole olemassa. Itse asiassa tämä johtuu staattisen menetelmän määritelmästä - koska se liittyy luokkaan, ei objektiin, $this pseudomuuttuja, joka osoittaa nykyiseen objektiin dynaamisissa menetelmissä, ei ole käytettävissä. Mikä on täysin loogista.

Sinun on kuitenkin tiedettävä, että toisin kuin muut kielet, PHP ei havaitse tilannetta "$tämä on kirjoitettu staattisella menetelmällä" jäsennys- tai käännösvaiheessa. Tällainen virhe voi tapahtua vain ajon aikana, jos yrität suorittaa koodia $this-koodilla staattisen menetelmän sisällä.

Koodi näin:
luokka A ( julkinen $id = 42; staattinen julkinen funktio foo() ( echo $this->id; ) )
ei aiheuta virheitä, kunhan et yritä käyttää foo()-menetelmää sopimattomasti:
$a = uusi A; $a->foo(); (ja saat välittömästi "Fatal error: Using $this kun ei ole objektikontekstissa")

Toinen ominaisuus on, että staattinen ei ole aksiooma!
luokka A ( staattinen julkinen funktio foo() ( echo 42; ) ) $a = uusi A; $a->foo();
Siinä se, kyllä. Staattista menetelmää, jos se ei sisällä $thitä koodissa, voidaan kutsua dynaamisessa kontekstissa, kuten objektimetodia. Tämä ei ole PHP:n virhe.

Käänteinen ei ole täysin totta:
luokka A ( julkinen funktio foo() ( echo 42; ) ) A::foo();
Dynaaminen menetelmä, joka ei käytä $thistä, voidaan suorittaa staattisessa kontekstissa. Saat kuitenkin varoituksen "Ei-staattista menetelmää A::foo():ta ei pidä kutsua staattisesti" tasolla E_STRICT. On sinun päätettävissäsi, noudatatko tiukasti koodistandardeja vai poistatko varoitukset. Ensimmäinen on tietysti parempi.

Ja muuten, kaikki edellä kirjoitettu koskee vain menetelmiä. Staattisen ominaisuuden käyttäminen "->" kautta on mahdotonta ja johtaa vakavaan virheeseen.

Kolmas merkitys, joka näyttää olevan vaikein - myöhäinen staattinen sidonta

Kehittäjät PHP kieli ei pysähtynyt kahteen arvoon avainsana"staattinen" ja versiossa 5.3 he lisäsivät kielen toisen "ominaisuuden", joka on toteutettu samalla sanalla! Sitä kutsutaan "late Static Binding" tai LSB (Late Static Binding).

Helpoin tapa ymmärtää LSB:n olemus on yksinkertaisilla esimerkeillä:

Luokkamalli ( julkinen staattinen $taulukko = "taulukko"; julkinen staattinen funktio getTable() ( palauttaa itsensä::$taulukko; ) ) echo Malli::getTable(); // "pöytä"
PHP:n self-avainsana tarkoittaa aina "sen luokan nimeä, jossa tämä sana kirjoitetaan". Tässä tapauksessa self korvataan malliluokalla ja self::$table mallilla::$taulukko.
Tätä kieliominaisuutta kutsutaan "varhaiseksi staattiseksi sidokseksi". Miksi aikaisin? Koska itsensä ja tietyn luokan nimen sitominen ei tapahdu ajon aikana, vaan aikaisemmissa vaiheissa - koodin jäsentämisessä ja kääntämisessä. No, "staattinen" - koska puhumme staattisista ominaisuuksista ja menetelmistä.

Muutetaan hieman koodiamme:

Luokkamalli ( julkinen staattinen $taulukko = "taulukko"; julkinen staattinen funktio getTable() ( palauttaa itsensä::$taulukko; ) ) luokka Käyttäjä laajentaa mallia ( julkinen staattinen $taulukko = "käyttäjät"; ) echo User::getTable() ; // "pöytä"

Nyt ymmärrät, miksi PHP käyttäytyy epäintuitiivisesti tässä tilanteessa. self liitettiin malliluokkaan, kun User-luokasta ei tiedetty mitään, ja siksi osoittaa malliin.

Mitä minun pitäisi tehdä?

Tämän ongelman ratkaisemiseksi "myöhäinen" sidosmekanismi keksittiin ajonaikaisessa vaiheessa. Se toimii hyvin yksinkertaisesti - kirjoita vain "staattinen" sanan "self" sijaan ja yhteys muodostetaan kutsuvan luokan kanssa. tämä koodi, eikä siellä, missä se on kirjoitettu:
class Malli ( julkinen staattinen $taulukko = "taulukko"; julkinen staattinen funktio getTable() ( palauttaa static::$table; ) ) class Käyttäjä laajentaa mallia ( julkinen staattinen $taulukko = "käyttäjät"; ) echo User::getTable() ; // "käyttäjät"

Tämä on mystinen "myöhäinen staattinen sidonta".

On huomattava, että PHP:n mukavuuden lisäämiseksi sanan "staattinen" lisäksi on myös erikoistoiminto get_ched_class(), joka kertoo, mikä luokka on kontekstissa Tämä hetki koodisi toimii.

Onnellisia haastatteluja!

Erittäin tärkeä ominaisuus OOP on läsnäolo staattiset ominaisuudet ja menetelmät. Tärkeintä on, että sinun on heti ymmärrettävä, mitä nämä ominaisuudet ja menetelmät eivät kuulu objektiin, vaan luokkaan. Tämä on ymmärrettävä alusta alkaen, mutta käyttämällä PHP:n staattisia ominaisuuksia ja menetelmiä Aion keskustella tässä artikkelissa.

Klassisin esimerkki on matemaattisista funktioista vastaava luokka. Jos joku tietää Java, silloin hän tietää, että siellä on luokka Matematiikka(V JavaScript on myös sellainen luokka), joka sisältää monia matemaattisia funktioita. Ja menetelmät ovat staattisia. Tämä tarkoittaa, että sinin tai eksponentin laskemiseksi sinun ei tarvitse luoda tämän luokan objektia, mikä on erittäin kätevää.

Kirjoita tästä luokasta pienempi kopio, mutta vain PHP:lle:

luokka matematiikka (
yksityinen staattinen $määrä = 0;
julkinen funktio __construct() (
itse::$count++;
}
julkinen staattinen funktio calcSin($x) (
return sin($x);
}
julkinen staattinen funktio calcSQRT($x) (
return sqrt($x);
}
julkinen staattinen funktio getCount() (
palauttaa itsensä::$count;
}
}
echo Math::calcSin(1);
kaiku"
";
echo Math::calcSQRT(9);
kaiku"
";
$math = new Math();
$matematiikka_2 = uusi matematiikka();
echo Math::getCount();
?>

Tässä koodissa näytin käyttämällä staattisia menetelmiä ja ominaisuuksia. Huomaa, että otin käyttöön klassisen objektilaskurimenetelmän. Tämä tapahtui vain siksi, että kenttä Kreivi on staattinen ja sillä on sama arvo kaikille objekteille.

Toinen suosittu esimerkki käyttämällä staattisia menetelmiä ja ominaisuuksia- tämä on kirjaamista. Kaikki merkinnät lisätään staattisilla menetelmillä. On myös hyvin yleistä luoda monista asetuksista koostuva luokka, ja sielläkin kaikki kentät ovat staattisia. Kuten näet, esimerkkejä käytöstä staattiset menetelmät ja ominaisuudet PHP:ssä ja muut kielet ovat enemmän kuin tarpeeksi, joten on välttämätöntä pystyä työskentelemään niiden kanssa.



Maailmassa on kahdenlaisia ​​PHP-kehittäjiä. Jotkut pitävät staattisista menetelmistä, koska niillä on helppo työskennellä, kun taas toiset päinvastoin pitävät staattisia menetelmiä pahoina eivätkä käytä niitä käytännössä.
Tässä artikkelissa yritän selittää useiden kehysten kanssa työskentelystäni saatuani kokemusta, miksi jotkut kehittäjät jättävät huomiotta parhaita käytäntöjä ja käyttää koko joukko staattisia menetelmiä.

Kuka rakastaa staattisia menetelmiä?

Niitä käyttävät erityisen usein kehittäjät, jotka ovat koskaan käyttäneet CodeIgniter-kehystä työssään.

Myös suurin osa Kohanan ja Laravelin kehittäjistä on tilastollisten menetelmien seuraajia.
Tässä emme voi olla mainitsematta sitä tosiasiaa, että ohjelmoijat, jotka päättävät alkaa kirjoittaa omia juttujaan, kieltäytyvät yleensä käyttämästä CodeIgniteriä.

Miksi kysyt?

CodeIgniter tuki PHP 4:ää ennen kuin staattiset menetelmät lisättiin PHP 5:een. Lisäksi CodeIgniter käyttää "superobjektia", joka antaa yhtäläisen pääsyn kaikkiin ohjaimelle määritettyihin luokkiin. Siten ne tulevat saataville käytettäväksi koko järjestelmässä.

Tämä tarkoittaa, että luokkiin pääsee mistä tahansa mallista käyttämällä __get()-metodia, joka etsii pyydetyn ominaisuuden käyttämällä get_instance()->($var). Aikaisemmin, kun __get()-funktiota ei tuettu PHP 4:ssä, tämä tehtiin käyttämällä foreach-rakennetta CI_Controller-parametrien kautta ja sitten kohdistamalla ne mallin $this-muuttujaan.

Kirjastossa sinun on kutsuttava get_instance. Kirjasto ei peri luokkaa väkisin joten __get()-funktiota ei voi ohittaa.

Äänenvoimakkuus…

Tämä johtaa melko hankalaan koodiin pääsyyn. Täsmälleen sama toiminnallisuus voidaan saavuttaa staattisella menetelmällä ilman ylimääräistä vaivaa.

Ja tällaisesta suunnittelusta ei ole erityistä syytä keskustella. Okei, voit käyttää mallisi istuntotietoja. Mutta miksi tekisit tämän?

"Ratkaisu"

Kohanan kehittäjät olivat ensimmäiset, jotka työskentelivät vakavasti staattisten menetelmien parissa. He tekivät seuraavat muutokset:
//oli $this->input->get("foo"); // muuttui Input::get("foo");
Tämä ei ole epätavallista monille CodeIgniter-kehittäjille, joilla on vanha PHP 4 ja jotka siirtyivät Kohana-kehykseen hyödyntääkseen kaikkia PHP 5:n etuja. Mutta mitä vähemmän merkkejä, sen parempi, eikö?

Joten mikä on ongelma?

Monet PHP-kehittäjät (etenkin Symfonyn ja Zendin hyvin perehtyneet) sanovat: "Se on ilmeistä - käytä riippuvuusinjektiota!" Mutta monilla CodeIgniter-yhteisön kehittäjillä ei ole todellista kokemusta tästä prosessista, koska se on melko monimutkainen.

Toinen tosiasia Fuel PHP -kehyksestä on se, että tähän asti enimmäkseen staattiset menetelmät toimivat käyttöliittymänä. Esimerkiksi logiikassa on edelleen ongelmia staatiikan kanssa, varsinkin kun kyseessä on HMVC-konsepti.

Tämä on pseudokoodi, jota en ole käyttänyt FuelPHP:ssä version 1.1 jälkeen:
Class ControllerA laajentaa Ohjainta ( julkinen toiminto action_foo() ( echo Input::get("param"); ​​​​) )
Ihan tavallinen koodi. Tämä menetelmä tulostaa arvon ?bar= menetelmässä.

Mitä tapahtuu, kun teemme HMVC-pyynnön tätä menetelmää?
luokka ControllerB laajentaa ohjaimen ( julkinen toiminto action_baz() ( echo Input::get("param"); ​​echo " & "; echo Request::forge("controllera/foo?param=val1")->execute() ; ) )
Soita selaimessa controllerb/baz, näet tulosteen "val1", mutta jos kirjoitat controllerb/baz?param=override, hanki sitten molemmat kutsut, jotta menetelmä palauttaa saman arvon.

Merkityksellisyys

Globaali koodi ei anna sinulle mitään yhteyttä. Esimerkki on parempi kuin mikään sana:
$this->request->input->get("param");
Pyydetty objekti sisältää täysin uuden esiintymän jokaiselle pyynnölle, sitten jokaiselle pyynnölle luodaan syöttöobjekti, joka sisältää vain tietyn pyynnön syöttötiedot. Tämä pätee FuelPHP 2.0 -suunnitelmien toimimiseen ja ratkaisee riippuvuusruiskutusongelman sekä HMVC-ongelmat.

Entä karkea syntaksi?

Symfony- tai Zend-kehittäjät eivät kärsi tästä, mutta CodeIgniteriä käyttävät näkevät painajaisia ​​"paluusta PHP 4:ään" pitkään.

$tämä viittaa aina "nykyiseen" objektiin, eikä sitä ehdottomasti pidä käyttää globaalin koodin käyttämiseen.

$this->request->input->get() saattaa näyttää CodeIgniter-syntaksin pitkältä muodolta, mutta itse asiassa olemme vain ohjaimessa. Kun ohjain instantoi sen sisällä olevan uuden kyselyn, kyselyn rakentaja vastaanottaa myös instanssin syötteenä.

Jos olet mallissa tai muussa luokassa, pääsy kuten $this->request->input->foo() ei toimi, koska $this ei ole ohjain.

Input::get("foo") -konstrukti luo julkisivun logiikkaesiintymille tausta. Mutta tämä ei ratkaise globaalin koodin toimintaan liittyviä ongelmia. Ne, jotka ovat laiskoja testaamaan sovelluksia, voivat vaihtaa kahden tilan välillä ilman, että heidän tarvitsee kokonaan käyttää uutta kehystä.

Taylor Otwellilta (luoja tai laravel 4) on loistava video, jossa hän kuvaa, kuinka voit korvata staattisen koodin yhdellä DiC-säilön kautta testatulla esiintymällä.

Laravel 4 – IoC-ohjaimen injektio ja yksikkötestaus UserScapesta Vimeossa.

Tämä on loistava esitys siitä, kuinka voit päästä eroon siitä, että et käytä staattisia menetelmiä Laravelissa. Vaikka jotkin nykyaikaiset puitteet ovat ensi silmäyksellä hyvin samanlaisia ​​kuin Kohana, ne ratkaisevat jopa tavallisimmat ongelmat täysin eri tavoilla.

Tällä surullisella asialla...

Olen parhaillaan muuntamassa PyroCMS:ää CodeIgniteristä Laraveliksi. Yritetään siirtyä suoraan maailmanlaajuisesta PHP 4 -koodista täydelliseen riippuvuusruiskeeseen on ehdoton itsemurha. Välivaihe ennen CI-lataimen käyttöä on PHP 5, PSR-2 automaattilatauskoodin käyttäminen staattisten menetelmien kanssa. No, toistaiseksi olemme edelleen CodeIgniterissä.

Siirtyminen staattisesta DiC-koodiin voidaan helposti osoittaa, kun siirrymme lopulta Laraveliin.

Siirtyminen tiukasti kytketystä CodeIgniter-koodista testattavaan PSR-2:een on suuri haaste. Pyro-tiimi on matkalla - ja se tulee olemaan eeppistä.

PHP:llä on kyky määritellä menetelmä staattiseksi. Staattisella menetelmällä ei ole pääsyä kohteen ominaisuuksiin. Tällaisia ​​menetelmiä voidaan kutsua vain luokan, ei objektin kontekstissa.

Tärkeintä on ymmärtää, että staattiset ominaisuudet ja menetelmät kuuluvat luokkiin, eivät objekteihin.

Esimerkki tekee sen heti selväksi. Luodaan matemaattinen objekti (lyhenne sanoista matematiikka englanniksi).

PHP staattiset menetelmät
"; $math_1 = new Math(); $math_2 = new Math(); $math_3 = new Math(); $math_4 = new Math(); echo "Luodut objektit: " . Math::getCount(); ?>

Tämä luokka tarjoaa työkaluja matemaattisten funktioiden käsittelyyn ilman objektin luomista. Luokassa on konstruktori, joka lisää staattista ominaisuutta $count yhdellä. Luokka muistaa tämän ominaisuuden arvon, koska se on staattinen.

Muuten, jos haluat määrittää menetelmän tai ominaisuuden staattiseksi, käytä sanaa staattinen , ja staattisen ominaisuuden saamiseksi käytä sanaa self, jota seuraa kaksoispiste "::".

Kaikki tämä ymmärretään paremmin vertaamalla, erityisesti vertaamalla toimivaa esimerkkiä virheelliseen. Laajennamme esimerkkiämme hieman.

PHP staattiset menetelmät laskuri++; ) julkinen staattinen funktio calcSin($x) ( paluu sin($x); ) julkinen staattinen funktio calcSQRT($x) ( paluu sqrt($x); ) julkinen staattinen funktio getCount() ( palauttaa itsensä::$count; ) julkinen funktio getCounter() ( palauttaa $this->counter; ) ) echo Math::calcSin(1); kaiku"
"; echo Math::calcSQRT(9); echo"
"; $math_1 = new Math(); $math_2 = new Math(); $math_3 = new Math(); $math_4 = new Math(); echo "Luodut objektit: " . Math::getCount(); echo "
"; echo "Luodut objektit: " . $math_4->getCounter(); ?>

Tässä esimerkissä lisäsimme luokkaan tavallisen $counter-ominaisuuden, jota myös lisäsimme yhdellä konstruktorissa. Mutta tavallinen ominaisuus kuuluu objektille, joten se ei säily objektien kutsujen välillä. Aina kun luokan (objektin) esiintymä luodaan, ominaisuus on yhtä suuri kuin nolla; konstruktorissa sitä kasvatetaan yhdellä.

Staattinen ominaisuus kuuluu luokkaan, joten sen arvo säilyy.

Alla on muutamia esimerkkejä, jotka osoittavat, kuinka staattiset ominaisuudet ja menetelmät toimivat.

Jos yritetään käyttää $this-muuttujaa staattisessa menetelmässä, seurauksena on virhe (Fataali virhe: $this käyttö, kun se ei ole objektikontekstissa).

PHP staattiset menetelmät ikä. "vanha."; // Tämä on virhe "Käytetään $thiä, kun se ei ole objektikontekstissa". ) ) $TestClass = new TestClass(); $TestClass->sayHei(); ?>

Muuten, ilman riviä:

$TestClass->sayHei();

Virhettä ei tapahdu, mutta heti kun yrität ajaa staattista menetelmää koodissasi olevan $this-muuttujan kanssa, saat välittömästi virheilmoituksen.

Jos poistat sanan staattinen tästä esimerkistä, virhettä ei tapahdu.

Jos käytät objektin ominaisuutta staattiselta menetelmältä, tämä johtaa virheeseen. Voit käyttää vain staattisia ominaisuuksia käyttämällä self::$age-rakennetta. Huomaa, että muuttujan nimen edessä on $-merkki, toisin kuin $this->age-konstruktissa.

PHP staattiset menetelmät sano Hei(); ?>

Jos tässä esimerkissä poistat sanan staattinen ominaisuuden nimen edessä, näkyviin tulee virheilmoitus "Pääsy ilmoittamattomaan staattiseen omaisuuteen".

Luokkaobjekteilla ei ole staattisia ominaisuuksia.

PHP staattiset menetelmät "; print_r($TestClass); echo""; ?>

Staattista menetelmää voidaan kutsua käyttämällä self::method() -rakennetta. Esimerkki:

PHP staattiset menetelmät tulosta Hei(); ?>

Staattinen ominaisuus voidaan saada luokan yhteydessä käyttämällä syntaksia:

echo TestClass::$ikä;

Lisäksi yritys päästä käsiksi tavalliseen omaisuuteen tällä tavalla johtaa virheeseen: "Fatal error: Pääsy ilmoittamattomaan staattiseen omaisuuteen."

Staattista ominaisuutta voidaan muuttaa luokan yhteydessä käyttämällä syntaksia:

TestClass::$ikä += 20; // Esimerkiksi

Toinen koodiesimerkki staattisilla menetelmillä ja ominaisuuksilla

Myös tässä esimerkissä yksinkertaisia ​​vaihtoehtoja käyttämällä staattisia menetelmiä ja ominaisuuksia. Mitä yksinkertaisempaa koodia ymmärrät, sitä paremmin muistat materiaalin.

PHP staattiset menetelmät ".TestClass::$age; // echo TestClass::$txt; // Virhe: Vakava virhe: Pääsy ilmoittamattomaan staattiseen ominaisuuteen. echo "
"; TestClass::sayHi(); echo"
"; TestClass::sayHello(); // Ja näin pääsin staattiseen muuttujaan objektin kautta ($obj::$age)... echo "
"; $obj = new TestClass; echo "Staattisen muuttujan käyttäminen objektin kautta: " . $obj::$age; ?>

Huomaa, ja tämä on tärkeää, että tässä esimerkissä käytimme ei-staattista sayHi()-metodia käyttämällä syntaksia staattisten luokan jäsenten käyttämiseen.

Yhteenveto

  • Pääasia: staattiset ominaisuudet kuuluvat luokkiin, ei objekteihin.
  • Staattisesta menetelmästä et pääse käsiksi luokan tavallisiin ominaisuuksiin ja menetelmiin; $this->name ei toimi tässä.
  • Staattisesta menetelmästä voit käyttää staattisia ominaisuuksia käyttämällä self::$name .
  • Luokan staattiset ominaisuudet eivät ole objektien käytettävissä.
  • Normaali menetelmä voi käyttää staattista ominaisuutta käyttämällä self::$name .
  • Staattinen ominaisuus voidaan saada luokan yhteydessä käyttämällä syntaksia: TestClass::$age .
  • Säännöllinen menetelmä voidaan kutsua sekä objektin ($object->method()) että luokan kontekstissa käyttämällä TestClass::method()-syntaksia.
  • $object::$age-syntaksin avulla pääsin staattiseen ominaisuuteen objektin kautta.

Rinnakkaiset JavaScriptin kanssa

JavaScriptissä on matemaattinen luokka, joka sisältää paljon erilaisia ​​matemaattisia toimintoja.

Matemaattisten laskutoimitusten suorittamiseksi (sinin tai eksponentin laskeminen) JavaScriptissä sinun ei tarvitse luoda Math-luokan objektia, koska sen menetelmät ovat staattisia. Ennen PHP:n oppiminen En ymmärtänyt mitä se oli, ja vasta opiskeltuani PHP:n luokkia ja objekteja kaikki loksahti paikoilleen päässäni.

On itse asiassa erittäin kätevää päästä suoraan Math-luokan matemaattisiin menetelmiin ilman, että tarvitsee luoda objektia.

Olen pitkään halunnut kirjoittaa tästä aiheesta. Ensimmäinen sysäys oli Miško Heveryn artikkeli "Static Methods are Death to Testability". Kirjoitin vastausartikkelin, mutta en koskaan julkaissut sitä. Mutta äskettäin näin jotain, jota voidaan kutsua "luokkakeskeiseksi ohjelmoimiseksi". Tämä virkistti kiinnostukseni aiheeseen ja tämä on tulos.

"Luokkasuuntautunut ohjelmointi" tarkoittaa, että käytetään luokkia, jotka koostuvat vain staattisista menetelmistä ja ominaisuuksista, eikä luokan esiintymää koskaan luoda. Tässä artikkelissa puhun seuraavista:

  • se ei tarjoa mitään etuja prosessiohjelmointiin verrattuna
  • älä luovu esineistä
  • staattisten luokan jäsenten läsnäolo = kuolema kokeisiin
Vaikka tämä artikkeli koskee PHP:tä, käsitteet koskevat myös muita kieliä.

Riippuvuudet

Yleensä koodi riippuu muusta koodista. Esimerkiksi:

$foo = substr($bar, 42);
Tämä koodi riippuu muuttujasta $bar ja substr-funktiosta. $bar on vain paikallinen muuttuja, joka on määritetty hieman korkeammalle samassa tiedostossa ja samassa laajuudessa. substr on PHP:n ydintoiminto. Täällä kaikki on yksinkertaista.

Nyt tämä esimerkki:

Luokka BloomFilter ( ... julkinen funktio __construct($m, $k) ( ... ) julkinen staattinen funktio getK($m, $n) ( return ceil(($m / $n) * log(2)); )... )
Tämä pieni aputoiminto tarjoaa yksinkertaisesti kääreen tietylle algoritmille, joka auttaa laskemaan hyvän luvun konstruktorissa käytetylle $k argumentille. Koska se on kutsuttava ennen luokan esiintymän luomista, sen on oltava staattinen. Tällä algoritmilla ei ole ulkoisia riippuvuuksia, eikä sitä todennäköisesti korvata. Sitä käytetään näin:

m $ = 10 000; $n = 2000; $b = uusi BloomFilter($m, BloomFilter::getK($m, $n));
Tämä ei luo ylimääräisiä riippuvuuksia. Luokka riippuu itsestään.

  • Vaihtoehtoinen rakentaja. Hyvä esimerkki on PHP:hen sisäänrakennettu DateTime-luokka. Sen ilmentymä voidaan luoda kahdella eri tavoilla:

    $date = new DateTime("2012-11-04"); $date = DateTime::createFromFormat("d-m-Y", "04-11-2012");
    Molemmissa tapauksissa tuloksena on DateTime-ilmentymä, ja molemmissa tapauksissa koodi on sidottu DateTime-luokkaan tavalla tai toisella. DateTime::createFromFormat staattinen menetelmä on vaihtoehtoinen objektikonstruktori, joka palauttaa saman asian kuin uusi DateTime , mutta lisätoiminnoilla. Jos voit kirjoittaa uuden luokan, voit kirjoittaa myös Class::method() . Tämä ei luo uusia riippuvuuksia.

  • Muut staattisten menetelmien käyttötavat vaikuttavat sitoutumiseen ja voivat luoda implisiittisiä riippuvuuksia.

    Muutama sana abstraktiosta

    Miksi kaikki tämä meteli riippuvuuksien kanssa? Abstraktiokyky! Kun tuotteesi kasvaa, sen monimutkaisuus lisääntyy. Ja abstraktio on avain monimutkaisuuden hallintaan.

    Sinulla on esimerkiksi sovellusluokka, joka edustaa sovellustasi. Se puhuu User-luokan kanssa, joka edustaa käyttäjää. Joka vastaanottaa tietoja tietokannasta. Tietokantaluokka tarvitsee DatabaseDriverin. DatabaseDriver tarvitsee yhteysparametrit. Ja niin edelleen. Jos kutsut vain Sovellus::start() staattisesti, joka kutsuu User::getData() staattisesti, joka kutsuu tietokantaa staattisesti ja niin edelleen ja toivot, että jokainen kerros selvittää riippuvuutensa, voit päätyä kauhea sotku, jos jokin menee pieleen, ei tällä tavalla. On mahdotonta arvata, toimiiko Application::start() kutsuminen, koska ei ole ollenkaan selvää, kuinka sisäiset riippuvuudet käyttäytyvät. Vielä pahempaa, ainoa tapa vaikuttaa Application::start():n toimintaan on muuttaa lähde tämä luokka ja sen kutsumien luokkien koodit ja luokkien koodit jotka kutsuvat näitä luokkia... talossa jonka Jack rakensi.

    Tehokkain tapa luoda monimutkaisia ​​sovelluksia on luoda erillisiä osia, joita voit rakentaa myöhemmin. Osia, joita voit lakata ajattelemasta, joihin voit luottaa. Esimerkiksi kun kutsutaan staattista Database::fetchAll(...) , ei ole takeita siitä, että yhteys tietokantaan on jo muodostettu tai muodostetaan.

    Funktio(tietokanta $tietokanta) ( ... )
    Jos tämän funktion sisällä oleva koodi suoritetaan, se tarkoittaa, että tietokantailmentymä on läpäissyt onnistuneesti, mikä tarkoittaa, että tietokantaobjektin ilmentymä luotiin onnistuneesti. Jos tietokantaluokka on suunniteltu oikein, voit olla varma, että tämän luokan esiintymän läsnäolo tarkoittaa kykyä suorittaa tietokantakyselyitä. Jos luokassa ei ole esiintymää, funktion runkoa ei suoriteta. Tämä tarkoittaa, että toiminnon ei pitäisi välittää tietokannan tilasta, vaan tietokantaluokka tekee tämän itse. Tämän lähestymistavan avulla voit unohtaa riippuvuudet ja keskittyä ongelmien ratkaisemiseen.

    Ilman kykyä olla ajattelematta riippuvuuksia ja näiden riippuvuuksien riippuvuuksia on lähes mahdotonta kirjoittaa mitään monimutkaista sovellusta. Tietokanta voi olla pieni kääreluokka tai jättimäinen monikerroksinen hirviö, jossa on joukko riippuvuuksia, se voi alkaa pienestä kääreestä ja muuntua jättimäiseksi hirviöksi ajan myötä, voit periä tietokantaluokan ja siirtää sen jälkeläisfunktiolle. , tällä ei ole merkitystä toiminnallesi (tietokanta $ tietokanta) , kunhan tietokannan julkinen käyttöliittymä ei muutu. Jos luokkasi on kunnolla erotettu muusta sovelluksesta riippuvuuslisäyksen avulla, voit testata jokaista niistä käyttämällä stubeja riippuvuuksien sijaan. Kun olet testannut luokkaa tarpeeksi varmistaaksesi, että se toimii odotetulla tavalla, voit poistaa sen arvailusta yksinkertaisesti tietäen, että sinun on käytettävä tietokanta-ilmentymää tietokannan kanssa työskentelemiseen.

    Luokkakeskeinen ohjelmointi on typerää. Opi käyttämään OOP:ta.