Omgekeerde schoonmaakvolgorde. Scriptbeëindiging - uitzondering

Er is zoveel water onder de brug gevlogen sinds PHP zichzelf tot OOP-taal heeft verklaard. Ik kon niet precies duidelijk maken wanneer, maar “Op 13 juli 2004 werd PHP 5 uitgebracht, mogelijk gemaakt door de nieuwe Zend Engine II. PHP 5 bevatte nieuwe functies, zoals verbeterde ondersteuning voor objectgeoriënteerd programmeren."
Dat wil zeggen, theoretisch gezien verschenen er toen al constructeurs en destructors. Zelf gebruik ik versie 5.3.2, maar ik ben verbaasd over wat het kan.

Een beetje over mezelf. Ik ben een C++ programmeur met 4 jaar ervaring. Specialisatie - computergraphics en netwerken. Namelijk de creatie netwerk spellen. Maar zulke spellen hebben een server nodig, en de server heeft een spelersbasis nodig. En de spelers willen ook een website. “Waarom een ​​webprogrammeur inhuren, ik ben zelf niet slecht. Tegelijkertijd leer ik de taal.”
Dat dacht ik een half jaar geleden ook, maar ik begrijp het nog steeds niet!

Klassiek
Ik denk dat velen die met destructors werkten ooit het volgende tegenkwamen:
PHP Fatale fout: uitzondering gegenereerd zonder stapelframe in Onbekend op regel 0
De eerste reactie is verbijstering. De tweede is mat. En overal op exit() drukken levert geen resultaat op, omdat de gok dat de uitzondering in de destructor niet onmiddellijk komt, en als dit gebeurt, dan is de codebasis hoogstwaarschijnlijk groot.
Antwoord van bugs.php.net/bug.php?id=33598
[e-mailadres beveiligd]:
Het genereren van uitzonderingen in __desctruct() is niet toegestaan.
Moet gedocumenteerd worden..
[e-mailadres beveiligd]:
Bedankt voor het rapport, en voor helpt ons onze documentatie te verbeteren.
"Pogingen om een ​​uitzondering te genereren vanuit een desctructor veroorzaken a fatale fout."
Grappig? Persoonlijk vind ik het niet echt leuk.
Het reproduceren van een fout met een impliciete uitzondering is heel eenvoudig.
klasse een
{
// ...
publieke functie __destruct()
{
globaal $_SESSION;
$_SESSION = "Wat informatie";
}
}
$dummy = nieuwe a();

^Let op: expliciete uitzonderingen werken soms correct. Ik ga experimenteren om te zien welk effect het heeft.

Omgekeerde schoonmaakvolgorde
Laten we de volgende code in een bepaalde reikwijdte hebben (algemeen en niet erg veel):
$aarde = nieuwe wereld();
$vasya = nieuwe mens($aarde);
Dienovereenkomstig wordt hij in de code van iemands constructeur in contact gebracht met de wereld. (Er wordt aangenomen dat Vasya zonder de wereld niet zal bestaan, laten we de filosofie terzijde schuiven, we moeten het project snel sluiten.)
Welnu, in de destructorcode Vasya ligt ala $this->my_world->RemoveHumanFromWorld($this), waarin RemoveAllMyStuff, CalculateKarma enzovoort worden aangeroepen. (Stel dat we geen link hebben met Vasya in onze wereld, aangezien dit niet vereist was binnen de reikwijdte van de taak)
Wat doet PHP als het buiten bereik valt? Vernietigt de wereld en crasht met de fout "Fatale fout: oproep naar een lidfunctie RemoveHumanFromWorld() op een niet-object in /home/god/my_projects/earth/creatures/reasonable/homo_sapiens.php op regel 1956."
(Daarom is de wereld trouwens in C++ geschreven, omdat God het niet nodig heeft om in welk universum dan ook te draaien. Virtuele ruimte met een vuilnisman. Ha Ha.)
Antwoord van bugs.php.net/bug.php?id=36759
[e-mailadres beveiligd]
Opgelost in CVS HEAD en PHP_5_2.
Ik wou dat ik deze Dmitry kon vinden en hem met zijn neus kon porren, zoals op die foto. Ik weet niet hoe het is in de nieuwste versies, ik heb nog niet geüpdatet, maar in 5.3 is het relevant.
Scriptbeëindiging - uitzondering
O, daar valt zoveel over te schrijven. Globale variabelen (ala-sessies) zijn niet langer geldig, toegang tot bestandssysteem wordt afgesneden. En in het algemeen, zoals ik het begrijp correcte werk script is niet gegarandeerd. Dus God verhoede dat je iets doet aan de vernietiging van een mondiaal object...
Maar laten we dat achterwege laten. De documentatie voor PHP 5.1 en eerder (ik kan de strofe en het vers niet vinden) zegt: "De destructor-methode zal worden aangeroepen zodra er geen andere verwijzingen naar een bepaald object zijn", wat in principe logisch is voor een taal zonder strikte vereisten voor de verwijderconstructie (lat. unset).
Na het bugrapport bugs.php.net/bug.php?id=38572
De documentatie is gewijzigd: "De destructormethode wordt aangeroepen zodra er geen andere verwijzingen naar een bepaald object zijn, of in welke volgorde dan ook tijdens de afsluitprocedure"
Comfortabel? Voor mij - niet heel veel.
Alleen directe links
Laten we, volgens de logica van de taal, object $a vóór $b verwijderen.
Maar laat het object $b een link opslaan naar het veld $a->some_data.
Dan zou object $b logischerwijs eerder moeten worden verwijderd. Helaas is dit niet het geval in PHP. Ik heb zo'n bug niet gevonden, maar de situatie is specifiek (en durf ik uitzonderlijk te zeggen). Het wordt vermeden door een zwakke plek tot aan de link naar $a, het is aanvaardbaar en ik heb het niet gerapporteerd.
Deadlock in PHP-stijl
$a->ref = $b;
$b->ref = $a;
Ooit was ik geïnteresseerd in hoe PHP om zou gaan met kruisverwijzingen. Zal het bevriezen? Krijgt u de foutmelding “u kunt de scope niet verlaten” en hoe klinkt dit in het Engels? Helaas heeft de kas aangetoond dat alle variabelen tot het einde zullen blijven bestaan, totdat het zover is, zoals ze zeggen, “of in welke volgorde dan ook tijdens de shutdown-reeks”
Conclusie
Op dit moment is dat alles wat ik me herinner. Of misschien wel alles wat ik ben tegengekomen. Maar ik kreeg de indruk dat destructors in PHP een steunpilaar zijn, dus hoogstwaarschijnlijk kom ik het binnenkort weer tegen.
Het lijkt mij dat de toekomst van OOP-webprogrammering in de C++-interpreter ligt, en misschien zal deze klaar zijn. Misschien zal iemand op een dag besluiten om C++ te veranderen, standaardconstructies toe te voegen zodat het webgericht wordt. Maar tot nu toe heb ik geen alternatieven gevonden.

De constructor van een klasse wordt automatisch aangeroepen wanneer instanties van de klasse en objecten uit de klasse worden gemaakt. In PHP OOP wordt de constructor gebruikt om eigenschappen te initialiseren tijdens het maken van objecten. De constructor ziet eruit als een gewone PHP-methode, het enige verschil is dat het begint met __ ( twee onderstrepingstekens).

Een PHP-klasseconstructor kan zoveel argumenten of parameters bevatten als nodig is. Het is ook mogelijk om een ​​constructor te definiëren zonder parameters.

Het is belangrijk op te merken dat de PHP-constructor slechts één keer wordt aangeroepen. En we kunnen de constructor niet expliciet aanroepen; deze wordt automatisch aangeroepen wanneer het object wordt gemaakt.

Om een ​​klasse te instantiëren gebruiken we trefwoord new, waarna de constructor wordt aangeroepen. In PHP wordt de ouderconstructor expliciet aangeroepen wanneer een afgeleide klassenconstructor wordt gedefinieerd. Als een superklasseconstructor vereist is, is een aanroep naar parent::__construct() vereist in de afgeleide klasse. Een superklasse-constructor kan worden geërfd als de afgeleide klasse zelf geen constructor definieert. De constructor wordt net als elke andere klassenmethode overgeërfd, tenzij deze in de superklasse privé is verklaard.

In PHP4 en lager werd bij het definiëren van een constructor een methode met dezelfde naam als de klasse gebruikt (zoals in C++ en Java). PHP5 OOP voor het definiëren van een constructor voor elke klasse bevat speciale functie __construeren() . De constructor kan argumenten bevatten volgens specifieke vereisten. Alle objecten kunnen een ingebouwde constructorfunctie hebben, die de eigenschappen ervan initialiseert wanneer een object wordt gemaakt. Met PHP kunt u slechts één constructor per klasse maken en we kunnen een constructor niet overbelasten.

Als er meerdere gedeclareerde constructors zijn, zal PHP de eerste aanroepen en de andere negeren. De constructor moet openbaar worden verklaard en kan buiten de klasse worden gebruikt. Als een constructor privé wordt verklaard, kan deze alleen worden gebruikt met de klasse waarin deze is gedefinieerd. Als we het privé moeten verklaren, zullen we een statische functieaanroep moeten gebruiken.

Omdat de constructor een magische methode is, zal deze aan het begin het onderscheidingsteken voor de magische methode hebben van twee onderstrepingstekens. Om een ​​constructor te definiëren, gebruiken we het construct-trefwoord:

Construct(); // Constructor zonder argumenten.

Voorbeeld van een PHP-constructor

Laten we aannemen dat we een PHP Human-klasse hebben en deze een naamvariabele bevat. De broncode ziet er als volgt uit:

Nu zullen we een constructor aan deze klasse toevoegen. Onthoud dat constructors in PHP OOP magische methoden zijn, daarom beginnen ze met twee onderstrepingstekens en het construct-trefwoord:

naam= $naamvanpersoon;

))

We maken objecten van deze klasse met behulp van het nieuwe trefwoord:

$firstObject = new Human("Joseph"); $secondObject= nieuwe Mens("Taylor"); In dit OOP PHP-voorbeeld hebben we objecten gemaakt en de variabele $name geïnitialiseerd. Het eerste object slaat de waarde op " Jozef", en de tweede -"

Taylor

". Om verwarring te voorkomen hebben we tijdens het maken waarden aan objecten toegewezen. Als er geen constructor zou zijn gedefinieerd voor de klasse Human, zouden objecten als volgt worden gemaakt:

$firstObject = nieuwe Mens();

$secondObject = nieuwe Mens();

PHP-constructor met meerdere argumenten

We voegen een nieuwe variabele, leeftijd, toe aan de klasse Human: Onze klasse bevat nu twee variabelen om gegevens voor elk object op te slaan. Naam en leeftijd worden weergegeven door de variabelen $name en $age . We definiëren de constructor opnieuw, maar deze keer met twee argumenten, één om de Name-instantie in te stellen en de andere om te verouderen: naam= $naamvanpersoon;

$dit -> leeftijd= $ageofperson;

) ) ?> $firstObject = new Human("Joseph", 23);

$secondObject= nieuwe Mens("Taylor", 35);

We hebben twee objecten gemaakt en deze bevatten de beginwaarden van twee lidvariabelen. Opgemerkt moet worden dat volgens

functie get_name() ( retourneert $deze->naam; ) functie get_age() ( retourneert $deze->leeftijd; )

Een compleet voorbeeld van het gebruik van een PHP OOP-klasseconstructor met vier functies:

naam= $naamvanpersoon;

$dit -> leeftijd= $ageofperson;

) function set_name($newname)( $this ->name=$newname; ) function set_age($newage)( $this ->age=$newage; ) function get_name())( return $this->name; ) function get_age ()( return $this->age; ) ) ?>

Nog een voorbeeld van een PHP-constructor

Eerst definiëren we een constructor voor de bookinfo-klasse. Wanneer de objecten zijn gemaakt, geven we de waarden voor de overeenkomstige instanties door aan de constructor.

Laten we eens kijken hoe de constructor wordt gebruikt. Eerst maken we een eenvoudige klasse met één eigenschap en één functie:

naam; ) ?>

Dit is een eenvoudige klasse die één gegevensvariabele bevat, de naam van de machine en een methode om deze naam weer te geven.

Laten we nu een constructor toevoegen die de naamwaarde instelt op het moment dat het object wordt gemaakt. In OOP PHP zou de constructorcode er als volgt uitzien:

functie __construct($param)( $deze->naam=$param; )

Door een constructor aan onze klasse toe te voegen, krijgen we de volgende code:

naam=$param;

) publieke functie get_carname() ( echo $this->name; ) ) ?>

Nu maken we een object van de klasse:

$mijnauto= nieuwe auto(“Honda”);

We geven de waarde van de variabele gegevens weer door de get_carname() methode aan te roepen:

$mijnauto->get_carname(); Het resultaat zal als volgt zijn: Honda.

Dit is een eenvoudig voorbeeld van het maken van een constructor die de waarde van de leden van een object initialiseert. Deze waarde staat niet vast. Indien nodig kunnen wij dit wijzigen. Echter, dit

geweldige manier

initialisatie van objecten.

Laten we de constructor gebruiken in het PHP OOP-objectvoorbeeld waar we eerder naar keken. In de bookinfo-klasse voegen we de volgende code toe:

functie __construct($param1, $ param2)( $this->price=$param1; $this->title=$param2; )

In het voorbeeld worden, na het toevoegen van deze code, instanties van de klasse geïnitialiseerd om objecten te maken. Dezelfde functionaliteit wordt bereikt met behulp van de constructor:

$astrologie->getBookTitle(); $programmering->getBookTitle(); $database->getBookTitle(); $astrologie->getBookPrice(); $programmering->getBookPrice(); $database->getBookPrice();

Deze PHP-code levert het volgende resultaat op:

Up-to-date astrologie
Up-to-date PHP
Up-to-date DB
25
36
17

Welkom bij de tweede les in de serie over OOP. In het eerste artikel heb je de basisprincipes van OOP in PHP geleerd, inclusief de concepten van klassen, methoden, velden en objecten. Je hebt ook geleerd hoe je een eenvoudige klasse kunt maken en deze kunt implementeren.

In dit artikel leert u nog meer over klassenmethoden en velden. Dit geeft je een goede basis om meer geavanceerde technieken zoals overerving te leren.

Hier is een lijst van wat ik je in dit artikel zal vertellen:

  • Constructors en destructors, waarmee u specifieke acties aan een object kunt toewijzen wanneer het wordt gemaakt en verwijderd;
  • Statische velden en methoden zijn die velden en methoden die niet zijn geassocieerd met specifieke objecten van een klasse;
  • Klasseconstanten, handig voor het opslaan van vaste waarden gerelateerd aan een specifieke klasse;
  • Een expliciete typeaanduiding die wordt gebruikt om beperkingen in te stellen op de typen parameters die aan een bepaalde methode kunnen worden doorgegeven;
  • Speciale methoden __get() en __set(), die worden gebruikt om de waarden van klassenvelden in te stellen en te lezen;
  • Een speciale methode __call() die wordt gebruikt om een ​​klassemethode aan te roepen.

Ben je klaar? Ga dan verder!

Constructeurs en destructeurs

Soms is het nodig om bepaalde acties gelijktijdig uit te voeren met het maken van een object. Het kan bijvoorbeeld zijn dat u direct bij het maken waarden voor de velden van een object moet instellen, of deze moet initialiseren met waarden uit de database.

Op dezelfde manier moet u mogelijk ook bepaalde acties uitvoeren om een ​​object uit het geheugen te verwijderen, zoals het verwijderen van objecten die afhankelijk zijn van het object dat wordt verwijderd, het sluiten van de databaseverbinding of het sluiten van bestanden.

Let op: hoe verwijder ik een object? PHP verwijdert automatisch een object uit het geheugen als er geen variabelen meer zijn die ernaar verwijzen. Als u bijvoorbeeld een nieuw voorwerp en sla het op in de variabele $myObject en verwijder het vervolgens met behulp van de unset($myObject) methode, het object zelf zal ook worden verwijderd. Als u een lokale variabele in een functie hebt gemaakt, wordt deze (samen met het object) verwijderd wanneer de functie wordt afgesloten.

PHP heeft twee speciale methoden die kunnen worden gebruikt om specifieke acties uit te voeren om objecten aan te maken en te verwijderen:

  • De constructor wordt onmiddellijk aangeroepen nadat u het object hebt gemaakt;
  • De destructor wordt strikt aangeroepen voordat het object uit het geheugen wordt verwijderd.

Werken met constructeurs

Gebruik constructors om de acties op te geven die moeten worden uitgevoerd om een ​​object van een klasse te maken. Deze acties kunnen het initialiseren van klassenvelden, het openen van bestanden en het lezen van gegevens omvatten.

Als u een constructor wilt maken, voegt u deze toe aan uw klasse speciale methode __construct() (twee onderstrepingstekens vóór het woord construct). PHP zal deze methode automatisch aanroepen wanneer u uw klasse implementeert, dat wil zeggen wanneer u een object van die klasse maakt.

Hier is een voorbeeldconstructor:

Class MyClass ( publieke functie __construct() ( echo "Ik ben zojuist gemaakt!"; ) ) $myObject = new MyClass(); // geeft weer "Ik" ben zojuist gemaakt!"

De klasse MyClass heeft een constructor die de tekenreeks 'Ik ben zojuist gemaakt!' op de pagina afdrukt. De laatste regel code maakt een nieuw object van de klasse MyClass aan. Wanneer dit gebeurt, roept PHP automatisch de constructor aan en wordt het bericht weergegeven. weergegeven in de browser Nu in de praktijk - initialisatieklassevelden:

Klaslid ( privé $gebruikersnaam; privé $locatie; privé $homepage; publieke functie __construct($gebruikersnaam, $locatie, $homepage) ( $dit->gebruikersnaam = $gebruikersnaam; $dit->locatie = $locatie; $dit- >homepage = $homepage ) publieke functie showProfile() ( echo "

"; echo"
Gebruikersnaam:
$deze->gebruikersnaam
"; echo"
Locatie:
$deze->locatie
"; echo"
Startpagina:
$dit->startpagina
"; echo"
"; ) ) $aMember = nieuw lid("fred", "Chicago", "http://example.com/"); $aMember->showProfile();

Dit script geeft het volgende op de pagina weer:

Gebruikersnaam: fred Locatie: Chicago Homepagina: http://example.com/

Onze Member-klasse heeft drie velden en een constructor die 3 waarden als parameters aanneemt: één voor elk veld. De constructor wijst de ontvangen waarden als argumenten toe aan de velden van het object. De klasse heeft ook een methode om de waarden van de velden van een object op de pagina weer te geven.

Vervolgens maakt de code een object van de klasse Member, waaraan we 3 waarden “fred”, “Chicago” en “http://example.com/” doorgeven, aangezien de constructor precies 3 parameters gebruikt. De constructor schrijft deze waarden naar de velden van het gemaakte object. Ten slotte wordt de methode showProfile() aangeroepen voor het gemaakte object om de resulterende waarden weer te geven.

Werken met destructors

Gebruik een destructor wanneer een object uit het geheugen wordt verwijderd. Mogelijk moet u het object in de database opslaan en sluiten bestanden openen, die interactie had met het object. Om een ​​destructor te maken, voegt u de methode __destruct() toe aan de klasse. Het wordt aangeroepen net voordat het object automatisch wordt verwijderd. Hier is een eenvoudig voorbeeld:

Class MyClass ( public function __destruct() ( echo "Ik sta op het punt te verdwijnen - tot ziens!"; // (geheugen wissen) ) ) $myObject = new MyClass(); unset($myObject); // geeft "I" weer "Ik sta op het punt te verdwijnen - tot ziens!"

We hebben een eenvoudige destructor gemaakt die een bericht op de pagina weergeeft. Vervolgens hebben we een object van onze klasse gemaakt en dit onmiddellijk verwijderd door de methode unset() aan te roepen op de variabele die naar het object verwijst. Vlak voordat het object werd verwijderd, werd de destructor gebeld, die het bericht "Ik sta op het punt te verdwijnen - tot ziens!" in de browser liet zien.

Opmerking: in tegenstelling tot constructors kunt u geen parameters doorgeven aan destructors.

De destructor wordt ook aangeroepen wanneer het script wordt afgesloten, omdat alle objecten en variabelen worden verwijderd wanneer de methode wordt afgesloten. De volgende code zal dus ook de destructor aanroepen:

Class MyClass ( public function __destruct() ( echo "Ik sta op het punt te verdwijnen - tot ziens!"; // (geheugen wissen) ) ) $myObject = new MyClass(); exit; // geeft "I" weer verdwijnen - tot ziens!"

Als het script stopt met draaien vanwege een fout, wordt ook de destructor aangeroepen.

Opmerking: bij het maken van objecten van een onderliggende klasse worden de constructors van de bovenliggende klasse niet automatisch aangeroepen. Alleen de constructeur van de erfgenaam zelf wordt gebeld. U kunt de constructor van de ouder echter als volgt vanuit een subklasse aanroepen:

ouder::__construct(). Hetzelfde geldt voor destructors. Je kunt de destructor van de ouder als volgt aanroepen: parent:__destruct(). In de volgende les over erfenis vertel ik je over ouder- en kindklassen.

Statische klassenvelden

We hebben statische variabelen besproken in het artikel PHP Variable Scope: alles wat u moet weten. Net als een reguliere lokale variabele is een statische variabele alleen toegankelijk binnen een functie. In tegenstelling tot reguliere lokale variabelen behouden statische variabelen echter hun waarden tussen functieaanroepen.

Statische klassenvelden werken volgens hetzelfde principe. Een statisch klassenveld is aan zijn klasse gekoppeld, maar behoudt zijn waarde gedurende het hele script. Vergelijk dit met gewone velden: ze zijn gekoppeld aan een specifiek object en gaan verloren als dat object wordt verwijderd.

Statische velden zijn handig in gevallen waarin u een specifieke waarde moet opslaan die van toepassing is op een hele klasse in plaats van op een afzonderlijk object. Ze zijn vergelijkbaar met globale klassevariabelen.

Om een ​​statische variabele te maken, voegt u het statische trefwoord toe aan de definitie:

Klasse MijnKlasse (openbare statische $myProperty; )

Hier is een voorbeeld van hoe statische variabelen werken:

Klassenlid ( privé $gebruikersnaam; openbare statische $numMembers = 0; openbare functie __construct($gebruikersnaam) ( $this->gebruikersnaam = $gebruikersnaam; self::$numMembers++; ) ) echo Lid::$numMembers . "
"; // geeft "0" $aMember = new Member("fred"); echo Member::$numMembers weer. "
"; // geeft "1" $anotherMember = new Member("mary"); echo Member::$numMembers weer. "
"; // geeft "2" weer

Er zijn een paar interessante dingen, dus laten we dit script eens bekijken:

  • De klasse Member heeft twee velden: het privéveld $username en het statische veld $numMembers, dat aanvankelijk is ingesteld op 0;
  • De constructor neemt het argument $username als parameter en stelt het veld van het nieuw gemaakte object in op de waarde van deze parameter. Tegelijkertijd verhoogt het de waarde van het veld $numMembers, waardoor duidelijk wordt dat het aantal objecten van onze klasse met 1 is toegenomen.

Merk op dat de constructor het statische veld als volgt benadert: self::$numMembers. Het trefwoord self is vergelijkbaar met $this, waar we in de vorige les naar hebben gekeken. Terwijl $this naar het huidige object verwijst, verwijst self naar de huidige klasse. Terwijl u -> gebruikt om toegang te krijgen tot de velden en methoden van een object, gebruikt u in dit geval :: om toegang te krijgen tot de velden en methoden van een klasse.

  • Ten slotte maakt het script verschillende objecten van de klasse Member en geeft hun nummer op de pagina weer, d.w.z. de waarde van de statische variabele $numMembers. Merk op dat deze variabele zijn waarde behoudt gedurende het hele script, ongeacht klasseobjecten.

Om toegang te krijgen tot een statisch veld van een klasse, gebruikt u dus de :: operator. Hier kunnen we het trefwoord self niet gebruiken omdat de code zich buiten de klasse bevindt, dus schrijven we de klassenaam, vervolgens :: en vervolgens de veldnaam (Member::$numMembers). Binnen de constructor moet je ook precies zo'n structuur gebruiken, en niet jezelf.

Opmerking: ons script kon gemakkelijk toegang krijgen tot het klassenveld $numMembers voordat het eerste object werd gemaakt van deze klasse. Het is niet nodig om objecten van een klasse te maken om de statische velden ervan te kunnen gebruiken.

Statische methoden

Naast statische klassenvelden kunt u ook statische methoden maken. Statische methoden worden, net als velden, geassocieerd met een klasse, maar het is niet nodig om een ​​object van de klasse te maken om een ​​statische methode aan te roepen. Dit maakt dergelijke methoden nuttig als u een klasse nodig heeft die niet op echte objecten werkt.

Om een ​​statische methode te maken, moet u het statische trefwoord aan de declaratie toevoegen:

Klasse MyClass ( openbare statische functie myMethod() ( // (acties) ) )

Ons vorige voorbeeld met betrekking tot statische velden was het statische veld $numMembers. Het is een goede gewoonte om velden privé te maken en de methoden om er toegang toe te krijgen. Laten we ons statische veld privé maken en een openbare statische methode schrijven om de waarde van het gegeven veld te verkrijgen:

Klassenlid ( privé $gebruikersnaam; privé statische $numMembers = 0; openbare functie __construct($gebruikersnaam) ( $this->gebruikersnaam = $gebruikersnaam; self::$numMembers++; ) openbare statische functie getNumMembers() ( return self::$ numMembers; ) ) echo Lid::getNumMembers() . "
"; // geeft "0" $aMember = new Member("fred"); echo Member::getNumMembers() weer. "
"; // geeft "1" $anotherMember = new Member("mary"); echo Member::getNumMembers() weer. "
"; // geeft "2" weer

Hier hebben we een statische methode getNumMembers() gemaakt die de waarde van het statische veld $numMembers retourneert. We hebben dit veld ook privé gemaakt, zodat de waarde ervan niet van buitenaf kan worden verkregen.

We hebben ook de aanroepcode gewijzigd om de methode getNumMembers() te gebruiken om de waarde van het veld $numMembers op te halen. Houd er rekening mee dat u kunt bellen deze methode zonder een klassenobject te maken, omdat de methode statisch is.

Klasse constanten

Met constanten kunt u een globale waarde instellen voor al uw code. Deze waarde staat vast en kan niet worden gewijzigd. Klasseconstanten zijn vergelijkbaar met reguliere constanten. Het belangrijkste verschil is dat een klasseconstante niet alleen globaal is, maar ook toegankelijk is vanuit de klasse waarin deze is gedefinieerd. Klasseconstanten zijn handig in gevallen waarin u specifieke waarden moet opslaan die tot een specifieke klasse behoren.

U kunt een klasseconstante definiëren met behulp van het const trefwoord. Bijvoorbeeld:

Klasse MijnKlasse ( const CONSTANT_NAME = waarde; )

Vervolgens kunt u toegang krijgen tot een klasseconstante via de klassenaam en de operator ::. Bijvoorbeeld zoals dit:

MijnKlas::CONSTANT_NAME

Opmerking: Net als bij statische velden en methoden kunt u toegang krijgen tot een constante met behulp van het trefwoord self.

Laten we klasseconstanten bekijken met een voorbeeld. Laten we constanten toevoegen aan de Member-klasse die de waarden van hun rol (deelnemer, moderator of beheerder) opslaan. Door constanten te gebruiken in plaats van reguliere numerieke waarden, hebben we de code beter leesbaar gemaakt. Hier is het script:

Klassenlid ( const LID = 1; const MODERATOR = 2; const ADMINISTRATOR = 3; privé $gebruikersnaam; privé $niveau; publieke functie __construct($gebruikersnaam, $niveau) ( $dit->gebruikersnaam = $gebruikersnaam; $dit-> level = $level ) public function getUsername() ( return $this->username; ) public function getLevel() ( if ($this->level == self::MEMBER) return "een lid"; if ($this) ->level == self::MODERATOR) retourneert "een moderator"; if ($this->level == self::ADMINISTRATOR) retourneert "een beheerder"; $aMember = nieuw lid(" fred ", Lid::LID); $anotherMember = new Member("mary", Lid::ADMINISTRATOR); echo $aMember->getUsername() . "is". $aMember->getLevel() . "
"; // toont "fred is een lid" echo $anotherMember->getUsername() . " is " . $anotherMember->getLevel() . "
"; // geeft weer "Mary is een beheerder"

We hebben drie klassenconstanten gemaakt: LID, MODERATOR en ADMINISTRATOR, en hebben deze respectievelijk de waarden 1, 2 en 3 gegeven. Vervolgens voegen we een veld $level toe om rollen op te slaan en passen we de constructor enigszins aan om ook dit veld te initialiseren. De klasse heeft ook een andere methode toegevoegd: getLevel(), die een specifiek bericht retourneert, afhankelijk van de waarde van het veld $level. Het vergelijkt deze waarde met elk van de klasseconstanten en retourneert de gewenste tekenreeks.

Het script maakt verschillende objecten met verschillende rollen. Om rollen aan objecten toe te wijzen, worden klasseconstanten gebruikt, en geen eenvoudige numerieke waarden. Vervolgens worden de methoden getUsername() en getLevel() voor elk object aangeroepen en worden de resultaten op de pagina weergegeven.

Expliciet specificeren van functieargumenttypen

In PHP hoef je geen gegevenstypen op te geven, dus je hoeft je geen zorgen te maken over welke argumenten je doorgeeft aan methoden. U kunt bijvoorbeeld veilig een numerieke waarde doorgeven aan de functie strlen(), die de lengte van een tekenreeks berekent. PHP converteert het getal eerst naar een string en retourneert vervolgens de lengte ervan:

Echostrlen(123); // toon "3"

Soms is het handig om het type expliciet op te geven, maar het kan tot bugs leiden die moeilijk op te lossen zijn, vooral als u met complexe gegevenstypen werkt, zoals objecten.

Bijvoorbeeld

Kijk naar deze code:

Klaslid ( privé $gebruikersnaam; publieke functie __construct($gebruikersnaam) ( $this->gebruikersnaam = $gebruikersnaam; ) publieke functie getUsername() ( return $this->gebruikersnaam; ) ) klasse Onderwerp ( privé $member; privé $onderwerp ; publieke functie __construct($member, $subject) ( $this->member = $member; $this->subject = $subject; ) publieke functie getUsername() ( return $this->member->getUsername(); ) ) $aMember = nieuw lid("fred"); $aTopic = nieuw onderwerp($aMember, "Hallo allemaal!"); echo $aTopic->getGebruikersnaam(); // zal "fred" weergeven

Dit script werkt als volgt:

  • We maken onze Member-klasse met een veld $username, een constructor en een getUsername() -methode;
  • We maken ook een Topic-klasse om forumartikelen te beheren. Het heeft twee velden: $member en $subject. $member is een object van de klasse Member, dit zal de auteur van het artikel zijn. Het veld $subject is het onderwerp van het artikel.
  • De klasse Topic bevat ook een constructor die een Member-object nodig heeft en een tekenreeks die het onderwerp van het artikel vertegenwoordigt. Het initialiseert de klassenvelden met deze waarden. Het heeft ook een getUsername() -methode, die de naam van het forumlid retourneert. Dit wordt bereikt door de methode getUsername() van het Member-object aan te roepen.
  • Ten slotte maken we een object van de klasse Member met de veldwaarde gebruikersnaam “fred”. Vervolgens maken we een object van de klasse Topic, waarbij we Fred en het onderwerp van het artikel "Hallo allemaal!" doorgeven. Ten slotte roepen we de methode getUsername() van de klasse Topic aan en geven we de gebruikersnaam (“fred”) op de pagina weer.

Dit is allemaal heel goed, maar...

Laten we het beter doen!

Laten we dit stukje code aan het einde toevoegen:

Klasse Widget ( privé $kleur; publieke functie __construct($color) ( $this->color = $color; ) publieke functie getColour() ( return $this->color; ) ) $aWidget = new Widget("blauw") ; $anotherTopic = nieuw onderwerp($aWidget, "Oeps!"); // geeft "Fatale fout: oproep aan ongedefinieerde methode Widget::getUsername()" echo $anotherTopic->getUsername();

Hier maken we een Widget-klasse met een $colour-veld, een constructor en een getColour()-methode die de kleur van de widget retourneert.

We zullen dan een object van deze klasse maken, gevolgd door een Topic-object met het argument $aWidget, terwijl we in feite de auteur van het artikel moeten doorgeven, d.w.z. Lidklasse-object.

Laten we nu proberen de methode getUsername() van de klasse Topic aan te roepen. Deze methode roept de methode getUsername() van de klasse Widget aan. En aangezien een dergelijke methode niet bestaat in deze klasse, krijgen we een foutmelding:

Fatale fout: oproep naar ongedefinieerde methode Widget::getUsername()

Het probleem is dat de oorzaak van de fout niet zo eenvoudig te begrijpen is. Waarom zoekt het Topic-object naar een methode in de Widget-klasse en niet naar Member? In een complexe klassenhiërarchie zal het erg moeilijk zijn om een ​​uitweg uit dit soort situaties te vinden.

Wij geven een hint

Het zou beter zijn om de Topic-constructor te beperken tot het accepteren van argumenten, zodat deze alleen Member-objecten als eerste parameter kan accepteren, waardoor fatale fouten worden voorkomen.

Dit is precies wat expliciete typespecificatie doet. Om het type van een parameter expliciet te specificeren, voegt u de klassenaam in vóór de argumentnaam in de methodedeclaratie:

Functie myMethod(ClassName $object) ( // (acties) )

Laten we de constructor van de klasse Topic aanpassen zodat deze alleen Member accepteert:

Klasse onderwerp ( privé $lid; privé $onderwerp; publieke functie __construct(Lid $lid, $onderwerp) ( $dit->lid = $lid; $dit->onderwerp = $onderwerp; ) publieke functie getGebruikersnaam() ( return $ this->lid->getUsername();

Laten we nu opnieuw proberen een Topic-object te maken en er een Widget aan door te geven:

$aWidget = nieuwe Widget("blauw"); $anotherTopic = nieuw onderwerp($aWidget, "Oeps!");

Deze keer zal PHP een specifieke foutmelding weergeven:

Opspoorbare fatale fout: Argument 1 doorgegeven aan Topic::__construct() moet een instance van Member zijn, instance van Widget opgegeven, aangeroepen in script.php op regel 55 en gedefinieerd in script.php op regel 24

Dit probleem zal veel gemakkelijker op te lossen zijn, omdat we precies weten wat de oorzaak van de fout is: we hebben geprobeerd een parameter van het verkeerde type aan de constructor door te geven. Het foutbericht toont zelfs de exacte coderegels waar de methode werd aangeroepen die de fout veroorzaakte.

Initialiseren en lezen van klasseveldwaarden met behulp van __get() en __set()

Zoals je al weet, bevatten klassen meestal velden:

Klasse MijnKlasse ( public $aProperty; public $anotherProperty; )

Als de velden van de klasse openbaar zijn, kunt u ze openen met de -> operator:

$myObject = nieuwe MijnKlasse; $myObject->aProperty = "hallo";

Met PHP kunt u echter “virtuele” velden maken die niet daadwerkelijk in de klasse voorkomen, maar toegankelijk zijn via de -> operator. Ze kunnen nuttig zijn in de volgende gevallen:

  • Wanneer u veel velden heeft en u er een array voor wilt maken, zodat u niet elk veld afzonderlijk hoeft te declareren;
  • Wanneer u een veld buiten een object moet opslaan, zoals in een ander object, of zelfs in een bestand of database;
  • Wanneer u veldwaarden direct moet berekenen, in plaats van de waarden ergens op te slaan.

Om zulke “virtuele” velden te creëren, moet je een aantal magische methoden aan de klasse toevoegen:

  • __get($propName) wordt automatisch aangeroepen wanneer wordt geprobeerd de waarde van het “onzichtbare” veld $propName te lezen;
  • __set($propName,$propValue) wordt automatisch aangeroepen wanneer wordt geprobeerd het “onzichtbare” veld $propName in te stellen op $propValue.

“Onzichtbaar” in in deze context Dit betekent dat u in dit codegedeelte niet rechtstreeks toegang hebt tot deze velden. Bijvoorbeeld als zo'n veld helemaal niet bestaat in de klasse, of als het wel bestaat, maar privé is, en er geen toegang is tot zo'n veld buiten de klasse.

Laten we verder gaan met oefenen. Laten we onze Member-klasse zo wijzigen dat er naast het $username-veld nog andere willekeurige velden zijn die worden opgeslagen in de $data-array:

Klassenlid ( private $gebruikersnaam; privé $data = array(); publieke functie __get($property) ( if ($property == "gebruikersnaam") ( return $this->gebruikersnaam; ) else ( if (array_key_exists($property , $this->data)) ( return $this->data[$property]; ) else ( return null; ) ) ) public function __set($property, $value) ( ​​if ($property == "gebruikersnaam ") ( $dit->gebruikersnaam = $waarde; ) else ( $dit->data[$property] = $waarde; ) ) ) $aMember = nieuw lid(); $aMember->gebruikersnaam = "fred"; $aMember->locatie = "San Francisco"; echo $aMember->gebruikersnaam . "
"; // geeft "fred" echo $aMember->location weer. "
"; // geeft "San Francisco" weer

Hier is hoe het werkt:

  • De Member-klasse heeft een constant veld private $username en een private array $data voor het opslaan van willekeurige “virtuele” velden;
  • De methode __get() gebruikt één enkele parameter $property: de naam van het veld waarvan de waarde moet worden geretourneerd. Als $property = “gebruikersnaam”, retourneert de methode de waarde van het veld $gebruikersnaam. Anders controleert de methode of een dergelijke eigenschap voorkomt in de sleutels van de array $data. Als een dergelijke sleutel wordt gevonden, retourneert deze de waarde van dit veld, anders - null.
  • De methode __set() gebruikt twee parameters: $property - de naam van het veld dat moet worden geïnitialiseerd, en $value - de waarde die moet worden ingesteld dit veld. Als $property = “gebruikersnaam”, initialiseert de methode het veld $username met de waarde uit de parameter $value. Voeg anders de sleutel $property met de waarde $value toe aan de array $data.
  • Nadat we de Member-klasse hebben gemaakt, maken we een object van deze klasse en initialiseren we het veld $username met de waarde “fred”. Hiermee wordt de methode __set() aangeroepen, die de waarde $username op het object zal instellen. Vervolgens stellen we de waarde van het veld $location in op “San Francisco”. Omdat een dergelijk veld niet bestaat in het object, schrijft de methode het naar de array $data.
  • Aan het einde halen we de waarden van $username en $location eruit en geven deze op de pagina weer. De methode __get() haalt de werkelijke waarde van $username op uit het bestaande veld $username en de waarde van $location uit de array $data.

Zoals u kunt zien, hebben we met behulp van de methoden __get() en __set() een klasse gemaakt die zowel echte als “virtuele” velden kan bevatten. Uit een stukje code waarin een waarde voor een bepaald veld is ingesteld, is het niet nodig om te weten of zo'n veld wel of niet in het object bestaat. Met de gebruikelijke -> operator kunt u een waarde voor een veld instellen of lezen.

Het voorbeeld laat ook zien hoe u eenvoudig methoden kunt maken, genaamd ‘getters’ en ‘setters’, om toegang te krijgen tot privévelden. We hoeven geen afzonderlijke methoden getUsername() en setUsername() te maken om toegang te krijgen tot het privéveld $username. In plaats daarvan hebben we de methoden __get() en __set() gemaakt om dit veld te manipuleren. Dit betekent dat we in totaal slechts 2 methoden nodig hebben, in plaats van 2 methoden per privéveld.

Opmerking: een woord over inkapseling. Het gebruik van privéklassevelden in combinatie met getters en setters is beter dan het gebruik van openbare variabelen. Getters en setters kunnen bovendien gegevens verwerken die van en naar de velden van een object worden gegeven, zoals controleren of een waarde het juiste formaat heeft of deze converteren naar vereiste formaat. Getters en setters verbergen ook de details van hoe de velden van een klasse worden geïmplementeerd, waardoor het gemakkelijker wordt om de interne onderdelen van een klasse te wijzigen, omdat u de code die op objecten van die klasse werkt niet hoeft te herschrijven. U wilt bijvoorbeeld ineens de waarde van een veld opslaan in een database. Als je al getters en setters had, hoef je ze alleen maar te herschrijven. En de belcode blijft hetzelfde. Deze techniek wordt inkapseling genoemd en is een van de belangrijkste voordelen van OOP.

Methoden overbelasten met __call()

Getters en setters worden gebruikt om de toegang tot privévariabelen te weigeren. In dezelfde richting wordt de methode __call() gebruikt om toegang tot privémethoden te weigeren. Telkens wanneer code een klassemethode aanroept die niet bestaat of niet beschikbaar is, wordt de methode __call() automatisch aangeroepen. Hier is de algemene syntaxis van de methode:

Openbare functie __call($methodName, $arguments) ( // (acties) )

Wanneer er wordt geprobeerd een niet-beschikbare klassemethode aan te roepen, roept PHP automatisch de methode __call() aan, waaraan het een string doorgeeft: de naam van de aangeroepen methode en een lijst met doorgegeven parameters in een array. Dan zal uw __call() methode dat moeten doen op een bepaalde manier de oproep verwerken en indien nodig waarden retourneren.

De methode __call() is handig in situaties waarin u bepaalde functionaliteit van een klasse aan een andere klasse moet doorgeven. Hier is een eenvoudig voorbeeld:

Klaslid ( privé $gebruikersnaam; publieke functie __construct($gebruikersnaam) ( $this->gebruikersnaam = $gebruikersnaam; ) publieke functie getUsername() ( return $this->gebruikersnaam; ) ) klasse Onderwerp ( privé $member; privé $onderwerp ; publieke functie __construct($member, $subject) ( $this->member = $member; $this->subject = $subject; ) publieke functie getSubject() ( retourneert $this->subject; ) publieke functie __call($ method, $arguments) ( return $this->member->$method($arguments); ) ) $aMember = new Member("fred"); $aTopic = nieuw onderwerp($aMember, "Hallo allemaal!"); echo $aTopic->getSubject() . "
"; // zal "Hallo iedereen!" weergeven echo $aTopic->getUsername() . "
"; // geeft "fred" weer

Dit voorbeeld is vergelijkbaar met het voorbeeld dat wordt gegeven in de sectie over het expliciet opgeven van typen. We hebben een Member-klasse met een veld $username en een Topic-klasse met een veld - een object van de Member-klasse (auteur van het artikel) en een veld $subject - het onderwerp van het artikel. De klasse Topic bevat een methode getSubject() om het onderwerp van een artikel op te halen, maar beschikt niet over een methode die de naam van de auteur van het artikel retourneert. In plaats daarvan heeft het een __call()-methode, die een niet-bestaande methode aanroept en argumenten doorgeeft aan de Member-klassemethode.

Wanneer uw code de methode $aTopic->getUsername() aanroept, begrijpt PHP dat een dergelijke methode niet bestaat in de klasse Topic. Daarom wordt de methode __call() aangeroepen, die op zijn beurt de methode getUsername() van de klasse Member aanroept. Deze methode retourneert de naam van de auteur naar de methode __call(), die de resulterende waarde naar de aanroepende code verzendt.

Opmerking: PHP heeft andere methoden die overbelasting aanpakken, zoals __isset(), __unset() en __callStatic().

Conclusie

In deze les heb je je kennis van OOP in PHP verdiept door velden en methoden in meer detail te bekijken. Je hebt gestudeerd:

  • Constructors en destructors, handig voor het initialiseren van velden en het wissen van geheugen nadat objecten zijn verwijderd;
  • Statische velden en methoden die op klassenniveau werken in plaats van op objectniveau;
  • Klasseconstanten, handig voor het opslaan van vaste waarden die nodig zijn op klasseniveau;
  • Expliciete indicatie van typen, waarmee u de typen argumenten kunt beperken die aan de methode worden doorgegeven;
  • De magische methoden __get(), __set() en __call(), die worden gebruikt om toegang te krijgen tot privévelden en methoden van een klasse. Door deze methoden te implementeren, kunt u “virtuele” velden en methoden creëren die niet in de klasse bestaan, maar die u tegelijkertijd kunt oproepen.

Met de kennis die u in deze en de voorgaande tutorials heeft opgedaan, kunt u beginnen met het schrijven van OOP. Maar dit is nog maar het begin! In de volgende les zullen we het hebben over de kracht van OOP: het vermogen van klassen om functionaliteit van andere klassen te erven.

Veel programmeerplezier!

De mogelijkheden van PHP zijn aanzienlijk breder vanwege de specifieke kenmerken ervan, maar zelfs in de bestaande implementatie geeft het de programmeur onbeperkte mogelijkheden. PHP-construct is een speciale methode van een klasse (object) die wordt aangeroepen telkens wanneer een instantie van de klasse wordt gemaakt.

De beperking is dat PHP werkt wanneer de pagina wordt gegenereerd. Op het moment dat een pagina wordt ververst of een andere pagina van dezelfde site wordt geladen, het juiste systeem objecten worden opnieuw vanaf nul gevormd.

Een instantie van een klasse maken

Hoeft geen constructeur te hebben. Als u de beginwaarden van variabelen moet voorbereiden, het moment moet vastleggen waarop een instantie van een klasse (object) wordt gemaakt en bepaalde acties op andere objecten moet uitvoeren, dan kunt u de PHP-klasseconstructiesyntaxis niet gebruiken en de code schrijven overeenkomstige code buiten de klassenmethoden.

Volgens de logica van de objectgeoriënteerde programmeerstijl moet elke klasse een constructor hebben; bovendien moet de klassenboom beginnen met de meest abstracte (absoluut lege) voorouder. geen goede praktijk.

Wanneer de stamboom begint met een betekenisvolle klasse die zijn eigen gegevens en eigenschappen heeft die verband houden met externe gegevens (objecten), is de functieconstructie van PHP onmisbaar.

IN in dit voorbeeld bij het maken (PHP-construct) van een instantie van de date-klasse, zal deze functie (constructor) worden aangeroepen. Het heeft een specifieke naam __construct en wordt slechts één keer automatisch aangeroepen wanneer een instantie van de klasse wordt gemaakt.

Deze klasse biedt een statische variabele $iUniqueNo, die in elk nieuw exemplaar van deze klasse een unieke waarde zal hebben. Instanties van klassen hebben niets met elkaar gemeen, behalve de beschrijving daarin PHP-syntaxis en de interactie van hun methoden geleverd door de ontwikkelaar.

Initialisatielogica overnemen

Elk object moet zijn doel verwezenlijken, hebben wat het moet hebben en doen wat het moet doen. Vanuit een dergelijk redelijk gezichtspunt kan initialisatie op elk niveau van de stamboom de initialisatie omvatten van elke voorouder die wordt opgeroepen vanaf het afstammelingsniveau.

In dit voorbeeld kunt u met het trefwoord parent:: de parent-constructor aanroepen vanaf het onderliggende niveau. De semantiek is eenvoudig. De voorouder moet eerst worden geïnitialiseerd en vervolgens de huidige instantie. De eerste volgt zijn eigen logica, de tweede volgt de zijne.

Wanneer elk object zijn eigen ding doet, algemeen proces ziet er correct en duidelijk uit. Maar deze regel mag niet als de norm voor alle systemen van objecten worden beschouwd.

De stamboom van het 'voedsel'-objectsysteem kan, bij een allereerste benadering, iets gemeen hebben, maar de producten melk, watermeloen, pasta en granen, hoewel ze tot een dergelijk systeem behoren, zien er totaal anders uit en worden compleet anders beschreven.

De ontwikkelaar moet elk objectsysteem bouwen op basis van het toepassingsgebied, en niet op basis van hoe het ooit door iemand is voorgesteld. Elke taak is uniek; de vereiste om een ​​PHP-ouderconstructie te gebruiken is niet absoluut.

Publieke en private bouwers

De constructor is standaard openbaar en kan door alle onderliggende items worden gebruikt. Het is niet nodig om dit aan te geven publieke functieconstructie, PHP behandelt standaard alles wat beschreven wordt als algemeen.

In hoeverre is het zinvol om het private trefwoord te gebruiken bij het beschrijven van constructors: is het specifiek voor de taak, een kenmerk van het ontwikkelingsproces of de voorkeuren van de programmeur?

Vanuit conceptueel oogpunt kan de stamboom van objecten enkele verboden voor voorouders met betrekking tot nakomelingen toestaan, maar het is moeilijk te zeggen of dit redelijke logica is, althans in de algemene context.

Levensduur van het object

Het concept van objectgeoriënteerd programmeren is breder dan de mogelijkheden van de PHP-constructklasse, om de eenvoudige reden dat deze laatste alleen bestaan ​​op het moment dat een pagina wordt gemaakt, opnieuw wordt gemaakt of een andere pagina op de site wordt gemaakt.

AJAX-deelname via Browser-JavaScript en de juiste code op de server zal de levensduur van objecten helpen verlengen, maar het zal in ieder geval een beperkte stijl zijn.

PHP biedt de mogelijkheid om een ​​script op de server uit te voeren wanneer de client de verbinding heeft verbroken, en om de client terug te laten keren naar het script dat het eerder uitvoerde, maar dit is helemaal geen optie wanneer het objectgeoriënteerde programma is geïmplementeerd in C++ .

IN het laatste geval kan worden gebouwd een volwaardig systeem objecten die “voor altijd” zullen bestaan ​​terwijl het programma actief is. Dit is echter het enige waar een stationaire programmeertaal als C++, C#, Pascal & Delphi op kan bogen. In de dynamische online wereld wordt alles anders gebouwd, leeft het sneller en bereikt meer.

Van serialisatie naar zelfbehoud

Je kunt een historische rechtvaardiging vinden voor de term ‘serialisatie’ en de verschijning in het dagelijks leven van het concept van ‘magische methoden’. Maar alles is veel eenvoudiger. Op precies dezelfde manier waarop de vrijheid van C++ verschilt van de rigiditeit van C#, verschilt serialisatie van banale concepten:

  • schrijf een object naar een string;
  • een object uit een string lezen.

Omring wat er wordt gezegd met magie en mythisch magische methoden- mooi, sonoor, maar niet erg praktisch. De wereld van informatie is vooral interessant omdat alles wat zichtbaar, hoorbaar en tastbaar is in eenvoudige en consistente tekst kan worden beschreven.

Informatie is altijd een reeks karakters geweest, is en zal altijd een reeks karakters zijn. Het maakt niet uit welke natuur. In de formele constructies van programmeertalen is de aard van symbolen hetzelfde: een coderingstabel.

Het idee om van een object een string te maken, zodat het, indien nodig, uit deze string kan worden hersteld zonder de essentie ervan te verliezen, is een zeer praktisch idee.

Van zelfbehoud naar zelfontwikkeling

Semantiek van de PHP-constructor binnen zijn syntaxis is beperkt, maar als de constructor wordt ontwikkeld vanuit een ontwikkelingspositie:

  • er is een begin: er wordt een compleet nieuw exemplaar gemaakt;
  • er is een huidige status: er wordt een reeds bestaand exemplaar gemaakt.

De beperkingen van PHP, vanwege het feit dat het systeem van objecten erop alleen bestaat op het moment van paginavorming, zullen vanzelf worden opgeheven.

Door bij het maken van een sitepagina een systeem van objecten te maken, kan deze worden opgeslagen. Voor de eenvoud hoeft dit proces niet serialisatie te worden genoemd; u ​​kunt zich beperken tot het opslaan van de huidige stand van zaken (database, bestanden), en wanneer u dezelfde pagina opnieuw moet maken of een andere op dezelfde site moet maken, hoeft u dat alleen maar te doen. het herstellen van de huidige staat van zaken die al is gevormd.

In deze context wordt een systeem van objecten slechts één keer gecreëerd en evolueert het eenvoudigweg tijdens de werking van de site. Met een dergelijk schema is het mogelijk een systeem van objecten te ontwerpen als iets dat zich aanpast aan veranderende bestaansomstandigheden.

Het zelfbehoudende objectsysteem “onthoudt” bezoekersacties en paginastatussen, en elke keer dat PHP wordt uitgevoerd, wordt het niet helemaal opnieuw gemaakt, maar hersteld naar een eerdere staat.

In het laatste artikel over objectgeoriënteerd programmeren in PHP hebben we de basis besproken OOP in PHP We hebben namelijk de concepten van klassen, objecten, eigenschappen en methoden bestudeerd - en we hebben geleerd te creëren eenvoudige lessen en objecten in PHP.

In het artikel van vandaag zullen we het hebben over ontwerpers En vernietigers V OOP.

Constructeurs

Wanneer u een instantie van een object maakt op basis van een klasse, moet u heel vaak een aantal handelingen uitvoeren basisinstellingen, of het nu gaat om het instellen van de eigenschappen van een object of het openen van configuratiebestanden, of wie weet wat nog meer. Het is voor deze doeleinden dat de constructormethode bestaat in OOP. In eerdere versies PHP5 de naam van de constructormethode viel samen met de naam van de klasse waartoe deze behoort, en beginnend met versie PHP5 de naam van de constructormethode moet worden aangeroepen __construeren()(dit zijn 2 onderstrepingstekens vóór het woord construct()).

De constructor wordt automatisch aangeroepen wanneer een object wordt gemaakt. Laten we proberen een klasse te maken die een methode zal bevatten __construeren():

Klasse MijnKlasse ( publieke functie __construct() ( echo "Ik ben zojuist gemaakt!"; ) ) $myObject = nieuwe MijnKlasse(); // zal afdrukken "Ik ben zojuist gemaakt!"

MyClass bevat een eenvoudige constructor die berichten afdrukt met behulp van de echo-instructie. In de laatste coderegel maken we een instantie van de klasse MyClass() en wanneer dit gebeurt, roept PHP automatisch de constructor aan en wordt het bericht "Ik ben zojuist gemaakt!"

Laten we nu naar een ander voorbeeld kijken, waarin wanneer een object wordt gemaakt, de eigenschappen ervan worden geïnitialiseerd:

Klasse Product( private $title; private $price; private $discount; public function __construct($title, $price, $discount) ( $this->title = $title; $this->price = $price; $this- >korting = $korting ) publieke functie getProduct() ( echo "Productnaam: "".$this->title."
"; echo "Artikelprijs: ".$this->prijs ." $
"; echo "Korting: ".$this->korting ."%
"; ) ) $product = new Product("Form Creator",20,25); $product->getProduct();

Als u dit script uitvoert, wordt de volgende informatie op het scherm weergegeven:

Productnaam: "Form Creation Wizard" Productprijs: 20$ Korting: 25%

Klas Product bevat 3 privé-eigendommen: $titel, $ prijs En $korting, en een constructor waaraan drie argumenten moeten doorgegeven worden: productnaam, productprijs en korting. Er is ook een methode getProduct() , waarin informatie over het product wordt weergegeven. De constructormethode gebruikt de pseudovariabele $this om waarden toe te wijzen aan de overeenkomstige eigenschappen van het object.

Vervolgens maken we een nieuw Product-object en geven daarin informatie over het product door. De constructor accepteert deze gegevens en stelt de juiste objecteigenschappen in. Ten slotte wordt de methode getProduct() aangeroepen, die de opgeslagen waarden van de eigenschappen van het object weergeeft.

Vernietigers

Net als bij constructors in PHP zijn er destructors die strikt worden aangeroepen voordat het object uit het geheugen wordt verwijderd.

Dit kan bijvoorbeeld nodig zijn om objecten te verwijderen die afhankelijk zijn van het object dat wordt verwijderd, om een ​​verbinding met een database te verbreken of om bestanden te sluiten.

Opmerking: PHP verwijdert automatisch een object uit het geheugen als er geen variabelen meer zijn die ernaar verwijzen. Als u bijvoorbeeld een nieuw object maakt en dit in een variabele opslaat $mijnObject en verwijder het vervolgens met behulp van de methode niet ingesteld($mijnObject) , dan wordt het object zelf ook verwijderd. Als u een lokale variabele in een functie hebt gemaakt, wordt deze (samen met het object) verwijderd wanneer de functie wordt afgesloten.

In tegenstelling tot constructors kun je geen parameters doorgeven aan destructors!

Om een ​​destructor te maken, voegt u een methode toe aan de klasse __vernietigen(). Hier is een eenvoudig voorbeeld:

Class MyClass ( publieke functie __destruct() ( echo "Ik ben een destructor. Het object is verwijderd. Dag!"; ) ) $myObject = new MyClass(); niet ingesteld($mijnObject); // geeft weer: "Ik ben een destructor. Het object is verwijderd. Dag!"

We hebben een eenvoudige destructor gemaakt die een bericht op de pagina weergeeft. Vervolgens hebben we een object van onze klasse gemaakt en dit onmiddellijk verwijderd door de methode aan te roepen uitgeschakeld() voor een variabele die naar een object verwijst. Vlak voordat het object werd verwijderd, werd de destructor aangeroepen, die een bericht in de browser liet zien "Ik ben een destructor. Het object is verwijderd. Dag!".

Er moet ook worden opgemerkt dat de destructor ook wordt aangeroepen bij het afsluiten van het script, omdat alle objecten en variabelen worden verwijderd bij het afsluiten van de methode. Laten we eens kijken naar een voorbeeld:

Class MyClass ( publieke functie __destruct() ( echo "Ik ben een destructor. Het object is verwijderd. Dag!"; ) ) $myObject = new MyClass(); Uitgang; // geeft weer: "Ik ben een destructor. Het object is verwijderd. Dag!"

Als het script vanwege een fout stopt met draaien, wordt ook de destructor aangeroepen.

Opmerking: Bij het maken van objecten van een onderliggende klasse worden de constructors van de bovenliggende klasse niet automatisch aangeroepen. Alleen de constructeur van de erfgenaam zelf wordt gebeld. U kunt de constructor van de ouder echter als volgt vanuit een subklasse aanroepen: ouder::__construct(). Hetzelfde geldt voor destructors. Je kunt de destructor van de ouder als volgt aanroepen: ouder:__destruct().

We zullen het hebben over het volgende in de volgende artikelen. Dat is alles voor vandaag!