Skip to content

3. De basisprincipes van PHP

3.1. De boomstructuur van de scripts

Image

3.2. Configuratie van PHP

PHP wordt vooraf geconfigureerd via een tekstbestand [php.ini]. Al deze instellingen kunnen programmatisch worden gewijzigd. De configuratie van PHP heeft een grote invloed op de uitvoering van de scripts. Het is daarom belangrijk om deze te kennen. Het volgende script [phpinfo.php] maakt dit mogelijk:

1
2
3
<?php

phpinfo();

Opmerkingen

  • regel 3: de functie [phpinfo] geeft de configuratie van PHP weer;

Resultaten van de uitvoering

"C:\myprograms\laragon-lite\bin\php\php-7.2.11-Win32-VC15-x64\php.exe" "C:\Data\st-2019\dev\php7\php5-exemples\exemples\tests\phpinfo.php"
phpinfo()
PHP Version => 7.2.11

System => Windows NT DESKTOP-528I5CU 10.0 build 17134 (Windows 10) AMD64
Build Date => Oct 10 2018 01:57:32
Compiler => MSVC15 (Visual C++ 2017)
Architecture => x64
Configure Command => cscript /nologo configure.js  "--enable-snapshot-build" "--enable-debug-pack" "--with-pdo-oci=c:\php-snap-build\deps_aux\oracle\x64\instantclient_12_1\sdk,shared" "--with-oci8-12c=c:\php-snap-build\deps_aux\oracle\x64\instantclient_12_1\sdk,shared" "--enable-object-out-dir=../obj/" "--enable-com-dotnet=shared" "--without-analyzer" "--with-pgo"
Server API => Command Line Interface
Virtual Directory Support => enabled
Configuration File (php.ini) Path => C:\windows
Loaded Configuration File => C:\myprograms\laragon-lite\bin\php\php-7.2.11-Win32-VC15-x64\php.ini
Scan this dir for additional .ini files => (none)
Additional .ini files parsed => (none)
Done.

De functie [phpinfo] geeft hier meer dan 800 configuratieregels weer. We zullen hier geen toelichting op geven, aangezien de meeste betrekking hebben op geavanceerd gebruik van PHP. Een belangrijke regel is regel 13 hierboven: deze geeft aan welk bestand [php.ini] is gebruikt om de PHP te configureren die u gaat gebruiken om uw scripts uit te voeren. Als u de uitvoerconfiguratie van PHP wilt wijzigen, moet u dit bestand aanpassen. In dit bestand staan talrijke opmerkingen die de rol van de verschillende configuraties toelichten.

3.3. Een eerste voorbeeld

3.3.1. De code

Hieronder vindt u een programma [bases-01.php] dat de eerste kenmerken van PHP laat zien.


<?php

// dit is een opmerking
// variabele gebruikt zonder te zijn gedeclareerd
$nom = "dupont";
// een schermweergave
print "nom=$nom\n";
// een array met elementen van verschillende typen
$tableau = array("un", "deux", 3, 4);
// het aantal elementen
$n = count($tableau);
// een lus
for ($i = 0; $i < $n; $i++) {
  print "tableau[$i]=$tableau[$i]\n";
}
// initialisatie van 2 variabelen met de inhoud van een array
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// samenvoeging van de 2 tekenreeksen
$chaine3 = $chaine1 . $chaine2;
// weergave van het resultaat
print "[$chaine1,$chaine2,$chaine3]\n";
// gebruik van een functie
affiche($chaine1);
// het type van een variabele kan bekend zijn
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// het type van een variabele kan tijdens de uitvoering veranderen
$n = "a changé";
afficheType("n", $n);
// een functie kan een resultaat retourneren
$res1 = f1(4);
print "res1=$res1\n";
// een functie kan een array met waarden retourneren
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// deze waarden hadden in een array kunnen worden opgeslagen
$t = f2();
for ($i = 0; $i < count($t); $i++) {
  print "t[$i]=$t[$i]\n";
}
// tests
for ($i = 0; $i < count($t); $i++) {
  // geeft alleen de tekenreeksen weer
  if (getType($t[$i]) === "string") {
    print "t[$i]=$t[$i]\n";
  }
}
// vergelijkingsoperatoren == en ===
if("2"==2){
  print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
  print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
  print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
  print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// andere tests
for ($i = 0; $i < count($t); $i++) {
  // geeft alleen gehele getallen >10 weer
  if (getType($t[$i]) === "integer" and $t[$i] > 10) {
    print "t[$i]=$t[$i]\n";
  }
}
// een while-lus
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
  print "t[$i]=$t[$i]\n";
  $somme += $t[$i];   //$somme=$somme+$t[$i]
  $i++;               //$i=$i+1
}//terwijl
print "somme=$somme\n";

// einde programma
exit;

//----------------------------------
function affiche($chaine) {
  // geeft $chaine weer
  print "chaine=$chaine\n";
}

//geeft weer
//----------------------------------
function afficheType($name, $variable) {
  // geeft het type weer van $variable
  print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}

//afficheType
//----------------------------------
function f1($param) {
  // telt 10 op bij $param
  return $param + 10;
}

//----------------------------------
function f2() {
  // geeft 3 waarden terug
  return array("un", 0, 100);
}
?>

De resultaten:


nom=dupont
tableau[0]=un
tableau[1]=deux
tableau[2]=3
tableau[3]=4
[chaine1,chaine2,chaine1chaine2]
chaine=chaine1
type[variable $n]=integer
type[variable $chaine1]=string
type[variable $tableau]=array
type[variable $n]=string
res1=14
(res1,res2,res3)=[un,0,100]
t[0]=un
t[1]=0
t[2]=100
t[0]=un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[2]=100
t[0]=8
t[1]=5
somme=13

Opmerkingen

  • regel 5: in PHP wordt het type van de variabelen niet gedeclareerd. Deze hebben een dynamisch type dat in de loop van de tijd kan variëren. $nom vertegenwoordigt de variabele met de identificatie 'nom';
  • regel 7: om iets op het scherm weer te geven, kan men de instructie print of de instructie echo gebruiken;
  • regel 9: met het sleutelwoord array kan een array worden gedefinieerd. De variabele $nom[$i] vertegenwoordigt het element $i van de array $tableau;
  • regel 11: de functie count($tableau) geeft het aantal elementen van de array $tableau weer;
  • regels 13-15: een lus. Aangezien deze slechts één instructie bevat, zijn de accolades hier optioneel. In het verdere verloop van dit document zullen we systematisch accolades gebruiken, ongeacht het aantal instructies;
  • regel 14: tekenreeksen worden tussen aanhalingstekens " of apostrofs ' geplaatst. Binnen aanhalingstekens worden de variabelen $variable geëvalueerd, maar niet binnen apostrofs;
  • regel 17: met de functie list kunnen variabelen in een lijst worden verzameld en met één enkele toewijzingsbewerking een waarde krijgen. Hier is $chaine1="string1" en $chaine2="string2";
  • regel 19: de operator . is de operator voor het samenvoegen van tekenreeksen;
  • regels 83-86: het sleutelwoord function definieert een functie. Een functie retourneert al dan niet waarden via de instructie return. De aanroepende code kan de resultaten van een functie negeren of ophalen. Een functie kan overal in de code worden gedefinieerd.
  • regel 92: de vooraf gedefinieerde functie getType($variable) retourneert een tekenreeks die het type van $variable weergeeft. Dit type kan in de loop van de tijd veranderen;
  • regel 45: de operator === vergelijkt twee elementen op strikte wijze: ze moeten van hetzelfde type zijn om vergeleken te kunnen worden. De operator == is minder streng: twee elementen kunnen gelijk zijn zonder van hetzelfde type te zijn. Dit wordt geïllustreerd door de instructies op de regels 50-60. Bij de operator == vindt de vergelijking plaats nadat de twee vergeleken elementen naar hetzelfde type zijn geconverteerd. Er vinden dan impliciete conversies plaats. Het is vrij gemakkelijk om de aanwezigheid van deze impliciete conversies te ‘vergeten’ en zo tot onvoorziene resultaten te komen, zoals ontdekken dat een voorwaarde waar is terwijl je verwachtte dat deze onwaar zou zijn. Om deze valkuil te vermijden, zullen we systematisch de vergelijkingsoperator === gebruiken;
  • regel 64: men kan ook de booleaanse operatoren or en ! gebruiken;
  • regel 69: in plaats van de notatie array() kan men de notatie [] gebruiken om een array te initialiseren vanuit PHP7;
  • regel 80: de vooraf gedefinieerde functie exit stopt de uitvoering van het script;
  • regel 107: de tag ?> geeft het einde van het script PHP aan. Deze is niet strikt noodzakelijk. Bovendien kan deze tag in een webcontext problemen opleveren als er spaties of regeleinden achter staan, die moeilijk te detecteren zijn omdat ze niet zichtbaar zijn in een teksteditor. Daarom zullen we deze tag in de rest van het document systematisch weglaten;

Opmerking: in dit document gebruiken we het trefwoord [print] om tekst op de console weer te geven. Een andere manier om hetzelfde te doen is door het trefwoord [echo] te gebruiken. Er zijn subtiele verschillen tussen deze twee trefwoorden, maar in de context van dit document maken die geen verschil. Als u dus liever [echo] gebruikt, doe dat dan gerust.

3.3.2. Gebruik van NetBeans

NetBeans geeft diverse waarschuwingen weer die het de moeite waard zijn om te controleren. Laten we het script [bases-01.php] als voorbeeld nemen:

Image

Op regel 5 geeft NetBeans een waarschuwing dat het bestand niet voldoet aan de aanbeveling PSR-1 (PHP Standaardaanbevelingen nr. 1). De PSR zijn aanbevelingen om standaardcode te produceren en zo de interoperabiliteit en het onderhoud van code die door verschillende personen is geschreven te vergemakkelijken. Het kan vervelend zijn om waarschuwingen te krijgen als men bewust van de standaarden wil afwijken, bijvoorbeeld omdat het projectteam andere standaarden hanteert. Wat je wel of niet wilt controleren met NetBeans, kun je instellen:

Image

  • in [5] staan de elementen die je met NetBeans wilt controleren;
  • in [6] staat de ernstgraad die is toegewezen aan de door NetBeans gemelde fout;

Image

In [7] is te zien dat is gevraagd om te controleren of de code de aanbevelingen PSR-0 en PSR-1 correct volgt. Er is niets verplicht. Tijdens de leerfase van de programmeertaal wordt aangeraden om zoveel mogelijk van de door NetBeans aangeboden opties te controleren. Zo leer je veel. Vervolgens pas je deze controle van NetBeans aan aan de coderingsnormen van het projectteam.

Laten we eens kijken naar de coderingsnormen PSR-1 en [8, 9]:

Optie
Controle
  1. Verklaring van klasse-constanten
Klasse-constanten MUST moeten in hoofdletters worden gedeclareerd, gescheiden door onderstrepingstekens.
Bijv.: const TAUX_TVA
  1. Methodedeclaratie
Methodenamen zoals MUST moeten worden gedeclareerd in camelCase().
Bijvoorbeeld: public function executeBatchImpots{}
  1. Eigenschapnaam
Eigenschapsnamen SHOULD moeten worden gedeclareerd in de indeling $StudlyCaps, $camelCase of $under_score (consequent binnen één scope)
Bijvoorbeeld: public SalaireAnnuel (StudlyCaps), public salaireAnnuel (camelCase), public salaire_annuel (under_score)
  1. Bijwerkingen
Een bestand SHOULD definieert nieuwe symbolen en veroorzaakt geen andere bijwerkingen, of het SHOULD voert logica uit met bijwerkingen, maar SHOULD NOT doet beide.
  1. Typeverklaring
Typenamen MUST moeten worden gedeclareerd in StudlyCaps (Code die is geschreven voor 5.2.x en eerder SHOULD maakt gebruik van de conventie voor pseudonamenruimten met Vendor_-voorvoegsels op typenamen). Elk type staat in een apart bestand en bevindt zich in een naamruimte van ten minste één niveau: een leveranciersnaam op het hoogste niveau.
Bijvoorbeeld: class EtudiantBoursier {}

De aanbeveling PSR-1 / 4 stelt dat in een bestand PHP het volgende moet staan:

  • ofwel de declaratie van een type (klassen, interface);
  • ofwel uitvoerbare code zonder declaratie van nieuwe typen;

Er zijn nog andere PHP-aanbevelingen die niet door NetBeans worden gecontroleerd: PSR-3, PSR-4, PSR-6, PSR-7 en PSR-13.

Omwille van het gemak wordt in de voorbeelden in dit document niet in alle gevallen voldaan aan aanbeveling PSR-1, omdat dit vereist dat de code van klassen en interfaces over afzonderlijke bestanden wordt verdeeld, wat voor eenvoudige voorbeelden te omslachtig is. Het is dan ook eenvoudiger om alles in één bestand onder te brengen. Voor het voorbeeld van de applicatie die als rode draad door dit document loopt, is getracht de aanbeveling PSR-1 zo goed mogelijk na te leven.

Sommige waarschuwingen van NetBeans wijzen op een mogelijke fout:

Image

De waarschuwing [Unitialized Variables] duidt op een waarschijnlijke fout, vaak een typefout in de naam van een variabele. Hetzelfde geldt voor de waarschuwing [Unused Variables].

Tot slot is het raadzaam om alle waarschuwingen van NetBeans te controleren die worden aangegeven door een paneel in de linkermarge van de code en een geel streepje in de rechtermarge:

Image

Image

3.4. Het bereik van variabelen

3.4.1. Voorbeeld 1

Het script [bases-02.php] ziet er als volgt uit:


<?php

// bereik van de variabelen

function f1() {
  // we gebruiken de globale variabele $i
  global $i;
  $i++;
  $j = 10;
  print "f1[i,j]=[$i,$j]\n";
}

function f2() {
  // er wordt gebruikgemaakt van de globale variabele $i
  global $i;
  $i++;
  $j = 20;
  print "f2[i,j]=[$i,$j]\n";
}

function f3() {
  // er wordt een lokale variabele $i gebruikt
  $i = 4;
  $j = 30;
  print "f3[i,j]=[$i,$j]\n";
}

// tests
$i = 0;
$j = 0;  // deze twee variabelen zijn alleen bekend in een functie f
// alleen als deze expliciet wordt gedeclareerd met de instructie global
// dat ze deze wil gebruiken
f1();
f2();
f3();
print "test[i,j]=[$i,$j]\n";

De resultaten:

1
2
3
4
f1[i,j]=[1,10]
f2[i,j]=[2,20]
f3[i,j]=[4,30]
test[i,j]=[2,0]

Opmerkingen

  • regels 29-30: definiëren twee variabelen, $i en $j, van het hoofdprogramma. Deze variabelen zijn niet bekend binnen de functies. Zo is in regel 9 de variabele $j van de functie f1 een lokale variabele van de functie f1 en verschilt deze van de variabele $j van het hoofdprogramma. Een functie kan via het sleutelwoord global toegang krijgen tot een variabele $variable van het hoofdprogramma;
  • regel 7 verwijst de instructie naar de globale variabele $i van het hoofdprogramma;

3.4.2. Voorbeeld 3

Het script [bases-03.php] luidt als volgt:


<?php

// het bereik van een variabele is globaal voor de codeblokken
$i = 0; {
  $i = 4;
  $i++;
}
print "i=$i\n";

De resultaten:

i=5

Opmerkingen

In sommige programmeertalen heeft een variabele die binnen accolades is gedefinieerd, slechts het bereik van die accolades: buiten die accolades is de variabele niet bekend. Uit bovenstaande resultaten blijkt dat dit in PHP niet het geval is. De variabele $i, die in regel 5 binnen de accolades is gedefinieerd, is dezelfde als die welke in de regels 4 en 8 buiten de accolades wordt gebruikt.

3.5. Typeveranderingen

De variabelen in PHP hebben geen constant type. Dit kan tijdens de uitvoering veranderen, afhankelijk van de waarde die aan de variabele wordt toegewezen. Bij bewerkingen met gegevens van verschillende typen voert de PHP-interpreter impliciete conversies uit om de operanden terug te brengen naar een gemeenschappelijk type. Deze impliciete conversies kunnen, als ze niet bekend zijn bij de ontwikkelaar, een bron van moeilijk op te sporen fouten zijn. Hieronder wordt een [bases-04.php]-script weergegeven dat impliciete en expliciete conversies laat zien:


<?php

// strikte typen bij het doorgeven van parameters
declare(strict_types=1);

// impliciete typeconversies
// type --> bool
print "Conversion vers un booléen------------------------------\n";
showBool("abcd", "abcd");
showBool("", "");
showBool("[1, 2, 3]", [1, 2, 3]);
showBool("[]", []);
showBool("NULL", NULL);
showBool("0.0", 0.0);
showBool("0", 0);
showBool("4.6", 4.6);

function showBool(string $prefixe, $var) : void {
  print "(bool) $prefixe : ";
  // de conversie van $var naar booleaanse waarde gebeurt automatisch in de daaropvolgende test
  if ($var) {
    print "true";
  } else {
    print "false";
  }
  print "\n";
}

Opmerkingen

  • regel 4: vraagt om een strikte typecontrole van de parameters van een functie wanneer deze is gespecificeerd;
  • regel 18: de functie [showBool] is bedoeld om de impliciete (automatische) transformatie te laten zien die de interpreter PHP uitvoert wanneer een waarde van welk type dan ook moet worden omgezet naar een booleaanse waarde (regel 21);
  • regel 18: aan de parameter $var is geen type toegewezen. De daadwerkelijke parameter kan dus van elk type zijn. De parameter $prefixe moet daarentegen van het type string zijn. De functie showBool retourneert geen waarde (void);
  • regel 21: in de instructie if($var) moet de waarde van $var worden omgezet naar een booleaanse waarde, zodat if kan worden geëvalueerd. Verrassend genoeg heeft de interpreter PHP een antwoord voor elk type waarde dat hem wordt gegeven;
  • regels 9-16: de waarde van de parameter van de functie [showBool] zal achtereenvolgens zijn:
    • regel 9: een niet-lege tekenreeks: resultaat TRUE (hoofdletters en kleine letters maken niet uit, TRUE = true);
    • regel 10: een lege tekenreeks: resultaat FALSE;
    • regel 11: een niet-lege array: resultaat TRUE;
    • regel 12: een lege array: resultaat FALSE;
    • regel 14: het reële getal 0: resultaat FALSE;
    • regel 15: het gehele getal 0: resultaat FALSE;
    • regel 16: het reële (of gehele) getal anders dan 0: resultaat TRUE;

Dit blijkt uit de verkregen schermweergaven:


Conversion vers un booléen------------------------------
(bool) abcd : true
(bool)  : false
(bool) [1, 2, 3] : true
(bool) [] : false
(bool) NULL : false
(bool) 0.0 : false
(bool) 0 : false
(bool) 4.6 : true

Laten we verdergaan met de scriptcode:


//
// impliciete conversies van het type string naar een numeriek type
// string --> getal
print "Conversion chaîne vers nombre------------------------------\n";
showNumber("12");
showNumber("45.67");
showNumber("abcd");

function showNumber(string $var) : void {
  $nombre = $var + 1;
  var_dump($nombre);
  print "($var): $nombre\n";
}

Opmerkingen

  • regel 9: de functie [showNumber] accepteert een parameter van het type string en retourneert geen resultaat (void);
  • regel 10: deze parameter wordt gebruikt in een rekenkundige bewerking, waardoor de interpreter PHP wordt gedwongen om $var om te zetten in een getal;
    • regel 5: zet de tekenreeks “12” om in het gehele getal 12;
    • regel 6: zet de tekenreeks “45.67” om in het reële getal 45.67;
    • regel 7: geeft een waarschuwing, maar zet de tekenreeks “abcd” toch om in het getal 0;

Dit zijn de resultaten van de uitvoering:

1
2
3
4
5
6
7
8
9
Conversion chaîne vers nombre------------------------------
int(13)
(12): 13
float(46.67)
(45.67): 46.67

Warning: A non-numeric value encountered in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_031.php on line 37
int(1)
(abcd): 1

Laten we verdergaan met de code van het script:


// expliciete typeconversies
// naar int
showInt("12.45");
showInt(67.8);
showInt(TRUE);
showInt(NULL);

function showInt($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((int) $var);
  print "\n";
}

Opmerkingen

  • regel 21: de functie [showInt] ontvangt een parameter van een willekeurig type en levert geen resultaat op. Ze probeert de parameter $var om te zetten in een geheel getal op regel 26. Over het algemeen geldt dat om een variabele $var om te zetten naar een type T, men (T) $var schrijft, waarbij T het volgende kan zijn: int, integer, bool, boolean, float, double, real, string, array, object, unset;
  • regel 16: zet de tekenreeks “12.45” om in het gehele getal 12;
  • regel 17: zet het reële getal 67,8 om in het gehele getal 67;
  • regel 18: zet de booleaanse waarde TRUE om in het gehele getal 1 (de booleaanse waarde FALSE in het gehele getal 0);
  • regel 19: zet de pointer NULL om in het gehele getal 0;

Dit is wat de schermuitvoer laat zien:

paramètre : string(5) "12.45"

résultat de la conversion : int(12)

paramètre : float(67.8)

résultat de la conversion : int(67)

paramètre : bool(true)

résultat de la conversion : int(1)

paramètre : NULL

résultat de la conversion : int(0)

We gaan verder met de analyse van het script met de expliciete conversie van waarden naar het type float:


// naar float
showFloat("12.45");
showFloat(67);
showFloat(TRUE);
showFloat(NULL);

function showFloat($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((float) $var);
  print "\n";
}

Opmerkingen

  • regel 35: de functie [showFloat] ontvangt een parameter van een willekeurig type en levert geen resultaat op;
  • regel 40: de waarde van deze parameter wordt expliciet omgezet in float;
  • regel 30: de tekenreeks “12.45” wordt omgezet in het reële getal 12.45;
  • regel 31: het gehele getal 67 wordt omgezet in het reële getal 67;
  • regel 32: de booleaanse waarde TRUE wordt omgezet in het reële getal 1 (de waarde FALSE in het getal 0);
  • regel 33: de pointer NULL wordt omgezet in het reële getal 0;

Dit blijkt uit de schermresultaten:

paramètre : string(5) "12.45"

résultat de la conversion : float(12.45)

paramètre : int(67)

résultat de la conversion : float(67)

paramètre : bool(true)

résultat de la conversion : float(1)

paramètre : NULL

résultat de la conversion : float(0)

We gaan verder met de uitleg van het script door conversies naar het type string te bekijken:


// naar string
showstring(5);
showString(6.7);
showString(FALSE);
showString(NULL);

function showString($var) : void {
  print "paramètre : ";
  var_dump($var);
  print "\n";
  print "résultat de la conversion : ";
  var_dump((string) $var);
  print "\n";
}
  • regel 49: de functie [showString] ontvangt een parameter van een willekeurig type en levert geen resultaat op;
  • regel 54: de waarde van de parameter wordt omgezet naar het type string;
  • regel 44: het gehele getal 5 wordt omgezet in de tekenreeks „5“;
  • regel 45: het reële getal 6,7 wordt omgezet in de tekenreeks „6,7“;
  • regel 46: de booleaanse waarde FALSE wordt omgezet in een lege tekenreeks;
  • regel 47: de pointer NULL wordt omgezet in een lege tekenreeks;

Dit zijn de schermresultaten:

paramètre : int(5)

résultat de la conversion : string(1) "5"

paramètre : float(6.7)

résultat de la conversion : string(3) "6.7"

paramètre : bool(false)

résultat de la conversion : string(0) ""

paramètre : NULL

résultat de la conversion : string(0) ""

3.6. De tabellen

3.6.1. Klassieke eendimensionale tabellen

Het script [bases-05.php] is als volgt:


<?php

// klassieke arrays
// initialisatie
$tab1 = array(0, 1, 2, 3, 4, 5);
// doorlopen - 1
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// doorlopen - 2
print "tab1 a " . count($tab1) . " éléments\n";
reset($tab1);
while (list($clé, $valeur) = each($tab1)) {
    print "tab1[$clé]=$valeur\n";
}
// elementen toevoegen
$tab1[] = $i++;
$tab1[] = $i++;
// doorlopen - 3
print "tab1 a " . count($tab1) . " éléments\n";
$i = 0;
foreach ($tab1 as $élément) {
  print "tab1[$i]=$élément\n";
  $i++;
}
// laatste element verwijderen
array_pop($tab1);
// doorloop - 4
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// eerste element verwijderen
array_shift($tab1);
// doorlopen - 5
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// toevoegen aan het einde van de tabel
array_push($tab1, -2);
// doorloop - 6
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}
// toevoegen aan het begin van de tabel
array_unshift($tab1, -1);
// doorloop - 7
print "tab1 a " . count($tab1) . " éléments\n";
for ($i = 0; $i < count($tab1); $i++) {
    print "tab1[$i]=$tab1[$i]\n";
}

De resultaten:


tab1 a 6 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 6 éléments

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_04.php on line 14
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1 a 8 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=7
tab1 a 7 éléments
tab1[0]=0
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1 a 6 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1 a 7 éléments
tab1[0]=1
tab1[1]=2
tab1[2]=3
tab1[3]=4
tab1[4]=5
tab1[5]=6
tab1[6]=-2
tab1 a 8 éléments
tab1[0]=-1
tab1[1]=1
tab1[2]=2
tab1[3]=3
tab1[4]=4
tab1[5]=5
tab1[6]=6
tab1[7]=-2

Opmerkingen

Het bovenstaande programma toont bewerkingen op een array van waarden. Er zijn twee notaties voor arrays in PHP:

$tableau=array("un",2,"trois")
$contraires=array("petit"=>"grand", "beau"=>"laid", "cher"=>"bon marché")

Tabel 1 wordt een array genoemd en tabel 2 een woordenboek of associatieve array, waarbij de elementen worden genoteerd als sleutel => waarde. De notatie $contraires["beau"] verwijst naar de waarde die bij de sleutel "mooi" hoort. Dat is hier dus de tekenreeks "lelijk". Tabel 1 is slechts een variant van het woordenboek en zou als volgt kunnen worden genoteerd:

$tableau=array(0=>"un",1=>2,2=>"trois")

Zo hebben we $tableau[2]="drie". Uiteindelijk zijn er alleen maar woordenboeken. In het geval van een klassieke array met n elementen zijn de sleutels de gehele getallen uit het interval [0,n-1].

  • regel 14: met de functie each($tableau) kan een woordenboek worden doorlopen. Bij elke aanroep retourneert deze functie een (sleutel, waarde)-paar uit het woordenboek. Zoals te zien is in regel 10 van de resultaten, is de functie each voortaan verouderd in PHP 7;
  • regel 13: de functie reset($dictionnaire) stelt de functie each in op het eerste (sleutel,waarde)-paar van het woordenboek.
  • regel 14: de lus while stopt wanneer de functie each aan het einde van het woordenboek een leeg paar retourneert. Hier vindt een impliciete conversie plaats: het lege paar wordt geconverteerd naar de booleaanse waarde FALSE;
  • regel 18: de notatie $tableau[]=waarde voegt het element valeur toe als laatste element van $tableau;
  • regel 23: de array wordt doorlopen met een foreach. Met dit syntactische element kan een woordenboek, en dus ook een array, op twee manieren worden doorlopen:
foreach($dictionnaire as $clé=>$valeur)
foreach($tableau as $valeur)

De eerste syntaxis retourneert bij elke iteratie een paar (clé,valeur), terwijl de tweede syntaxis alleen het element valeur uit het woordenboek retourneert.

  • regel 28: de functie array_pop($tableau) verwijdert het laatste element uit $tableau;
  • regel 35: de functie array_shift($tableau) verwijdert het eerste element uit $tableau;
  • regel 42: de functie array_push($tableau,waarde) voegt valeur toe als laatste element van $tableau;
  • regel 49: de functie array_unshift($tableau,waarde) voegt valeur toe als eerste element van $tableau;

3.6.2. Het woordenboek of associatieve array

Het script [bases-06.php] is als volgt:


<?php

// woordenboeken
$conjoints = ["Pierre" => "Gisèle", "Paul" => "Virginie", "Jacques" => "Lucette", "Jean" => ""];
// doorloop - 1
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
    print "conjoints[$clé]=$valeur\n";
}
// sorteren van het woordenboek op de sleutel
ksort($conjoints);
// doorloop - 2
reset($conjoints);
while (list($clé, $valeur) = each($conjoints)) {
    print "conjoints[$clé]=$valeur\n";
}
// lijst met sleutels van het woordenboek
$clés = array_keys($conjoints);
for ($i = 0; $i < count($clés); $i++) {
    print "clés[$i]=$clés[$i]\n";
}
// lijst met waarden van het woordenboek
$valeurs = array_values($conjoints);
for ($i = 0; $i < count($valeurs); $i++) {
    print "valeurs[$i]=$valeurs[$i]\n";
}
// zoeken naar een sleutel
existe($conjoints, "Jacques");
existe($conjoints, "Lucette");
existe($conjoints, "Jean");
// een sleutel-waarde verwijderen
unset($conjoints["Jean"]);
print "Nombre d'éléments du dictionnaire : " . count($conjoints) . "\n";
foreach ($conjoints as $clé => $valeur) {
  print "conjoints[$clé]=$valeur\n";
}
// einde
exit;

function existe($conjoints, $mari) {
  // controleert of de sleutel $mari voorkomt in het woordenboek $conjoints
  if (isset($conjoints[$mari])) {
        print "La clé [$mari] existe associée à la valeur [$conjoints[$mari]]\n";
    } else {
        print "La clé [$mari] n'existe pas\n";
    }
}

De resultaten:


Nombre d'éléments du dictionnaire : 4

Deprecated: The each() function is deprecated. This message will be suppressed on further calls in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_05.php on line 8
conjoints[Pierre]=Gisèle
conjoints[Paul]=Virginie
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Jacques]=Lucette
conjoints[Jean]=
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle
clés[0]=Jacques
clés[1]=Jean
clés[2]=Paul
clés[3]=Pierre
valeurs[0]=Lucette
valeurs[1]=
valeurs[2]=Virginie
valeurs[3]=Gisèle
La clé [Jacques] existe associée à la valeur [Lucette]
La clé [Lucette] n'existe pas
La clé [Jean] existe associée à la valeur []
Nombre d'éléments du dictionnaire : 3
conjoints[Jacques]=Lucette
conjoints[Paul]=Virginie
conjoints[Pierre]=Gisèle

Opmerkingen

De bovenstaande code past op een woordenboek toe wat eerder is behandeld voor een eenvoudige array. We geven alleen uitleg bij de nieuwe elementen:

  • regel 12: met de functie ksort (key sort) kan een woordenboek worden gesorteerd in de natuurlijke volgorde van de sleutels;
  • regel 19: de functie array_keys($dictionnaire) geeft de lijst met sleutels van het woordenboek weer in de vorm van een array;
  • regel 24: de functie array_values($dictionnaire) geeft de lijst met waarden van het woordenboek weer in de vorm van een tabel;
  • regel 43: de functie isset($variable) retourneert TRUE als de variabele $variable is gedefinieerd, anders FALSE;
  • regel 33: de functie unset($variable) verwijdert de variabele $variable.

3.6.3. Meerdimensionale tabellen

Het script [bases-07.php] is als volgt:


<?php

// klassieke multidimensionale tabellen
// initialisatie
$multi = array(array(0, 1, 2), array(10, 11, 12, 13), array(20, 21, 22, 23, 24));
// doorloop
for ($i1 = 0; $i1 < count($multi); $i1++) {
  for ($i2 = 0; $i2 < count($multi[$i1]); $i2++) {
    print "multi[$i1][$i2]=" . $multi[$i1][$i2] . "\n";
  }
}
// multidimensionale woordenboeken
// initialisatie
$multi = array("zéro" => array(0, 1, 2), "un" => array(10, 11, 12, 13), "deux" => array(20, 21, 22, 23, 24));
// doorlopen
foreach ($multi as $clé => $valeur) {
    for ($i2 = 0; $i2 < count($valeur); $i2++) {
        print "multi[$clé][$i2]=" . $multi[$clé][$i2] . "\n";
    }
}

Resultaten:


multi[0][0]=0
multi[0][1]=1
multi[0][2]=2
multi[1][0]=10
multi[1][1]=11
multi[1][2]=12
multi[1][3]=13
multi[2][0]=20
multi[2][1]=21
multi[2][2]=22
multi[2][3]=23
multi[2][4]=24
multi[zéro][0]=0
multi[zéro][1]=1
multi[zéro][2]=2
multi[un][0]=10
multi[un][1]=11
multi[un][2]=12
multi[un][3]=13
multi[deux][0]=20
multi[deux][1]=21
multi[deux][2]=22
multi[deux][3]=23
multi[deux][4]=24

Opmerkingen

  • regel 5: de elementen van de array $multi zijn zelf arrays;
  • regel 14: de tabel $multi wordt een woordenboek (clé,valeur) waarin elke valeur een tabel is;

3.7. De tekenreeksen

3.7.1. Notatie

Het script [bases-08.php] luidt als volgt:


<?php

// notatie van strings
$chaine1 = "un";
$chaine2 = 'un';
print "[$chaine1,$chaine2]\n";
?>

Resultaten:

[un,un]

3.7.2. Vergelijking

Het script [bases-09.php] is als volgt:


<?php

// strikte naleving van het type van de functieparameters
declare(strict_types=1);

// vergelijkingsfunctie
function compareModele2Chaine(string $chaine1, string $chaine2): void {
  // vergelijkt string1 en string2
  if ($chaine1 === $chaine2) {
    print "[$chaine1] est égal à [$chaine2]\n";
  } else {
    print "[$chaine1] est différent de [$chaine2]\n";
  }
}

// tests voor het vergelijken van tekenreeksen
compareModele2Chaine("abcd", "abcd");
compareModele2Chaine("", "");
compareModele2Chaine("1", "");
exit;

Resultaten:


[abcd] est égal à [abcd]
[] est égal à []
[1] est différent de []

Opmerkingen

  • regel 9 van de code: men had de vergelijkingsoperator == kunnen gebruiken in plaats van ===. Deze laatste operator is strenger in die zin dat hij vereist dat beide operanden van hetzelfde type zijn. Merk op dat hij hier vervangen had kunnen worden door de operator ==, aangezien het type van beide parameters in de functiesignatuur is vastgesteld op string;

3.7.3. Koppelingen tussen strings en arrays

Het script [bases-10.php] is als volgt:


<?php

// tekenreeks naar array
$chaine = "1:2:3:4";
$tab = explode(":", $chaine);
// doorlopen van een array
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
}
// array naar tekenreeks
$chaine2 = implode(":", $tab);
print "chaine2=$chaine2\n";
// een leeg veld toevoegen
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// doorlopen van een array
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
} // we hebben nu 5 elementen, waarvan het laatste leeg is
// laten we opnieuw een leeg veld toevoegen
$chaine .= ":";
print "chaîne=$chaine\n";
$tab = explode(":", $chaine);
// doorloop de array
print "tab a " . count($tab) . " éléments\n";
for ($i = 0; $i < count($tab); $i++) {
    print "tab[$i]=$tab[$i]\n";
} // we hebben nu 6 elementen, waarvan de laatste twee leeg zijn

Resultaten:


tab a 4 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
chaine2=1:2:3:4
chaîne=1:2:3:4:
tab a 5 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
chaîne=1:2:3:4::
tab a 6 éléments
tab[0]=1
tab[1]=2
tab[2]=3
tab[3]=4
tab[4]=
tab[5]=

Opmerkingen

  • regel 5: met de functie explode($séparateur,$chaine) kunnen de velden van $chaine worden opgehaald, gescheiden door $séparateur. Zo haalt explode(":",$chaine) de elementen van $chaine die gescheiden zijn door de tekenreeks ":" op in de vorm van een array;
  • regel 12: de functie implode($séparateur,$tableau) voert de omgekeerde bewerking uit van de functie explode. Deze functie retourneert een tekenreeks die bestaat uit de elementen van $tableau, gescheiden door $séparateur;

3.7.4. Reguliere expressies

Het script [bases-11.php] is als volgt:


<?php

// strikte typecontrole voor functieparameters
declare (strict_types=1);

// reguliere expressies in PHP
// de verschillende velden uit een tekenreeks ophalen
// het patroon: een reeks cijfers omgeven door willekeurige tekens
// we willen alleen de reeks cijfers ophalen
$modèle = "/(\d+)/";
// we vergelijken de tekenreeks met het patroon
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");

// het patroon: een reeks cijfers omgeven door willekeurige tekens
// we willen de reeks cijfers en de velden ervoor en erna
$modèle = "/^(.*?)(\d+)(.*?)$/";
// we vergelijken de tekenreeks met het patroon
compareModele2Chaine($modèle, "xyz1234abcd");
compareModele2Chaine($modèle, "12 34");
compareModele2Chaine($modèle, "abcd");

// het patroon – een datum in de notatie dd/mm/jj
$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";
compareModele2Chaine($modèle, "10/05/97");
compareModele2Chaine($modèle, "  04/04/01  ");
compareModele2Chaine($modèle, "5/1/01");

// het patroon – een decimaal getal
$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";
compareModele2Chaine($modèle, "187.8");
compareModele2Chaine($modèle, "-0.6");
compareModele2Chaine($modèle, "4");
compareModele2Chaine($modèle, ".6");
compareModele2Chaine($modèle, "4.");
compareModele2Chaine($modèle, " + 4");

// einde
exit;

// --------------------------------------------------------------------------
function compareModele2Chaine(string $modèle, string $chaîne): void {
  // vergelijkt de tekenreeks $chaîne met het sjabloon $modèle
  // de tekenreeks wordt vergeleken met het patroon
  $champs = [];
  $correspond = preg_match($modèle, $chaîne, $champs);
  // weergave van de resultaten
  print "\nRésultats($modèle,$chaîne)\n";
  if ($correspond) {
    for ($i = 0; $i < count($champs); $i++) {
      print "champs[$i]=$champs[$i]\n";
    }
  } else {
    print "La chaîne [$chaîne] ne correspond pas au modèle [$modèle]\n";
  }
}

Resultaten:


Résultats(/(\d+)/,xyz1234abcd)
champs[0]=1234
champs[1]=1234

Résultats(/(\d+)/,12 34)
champs[0]=12
champs[1]=12

Résultats(/(\d+)/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/(\d+)/]

Résultats(/^(.*?)(\d+)(.*?)$/,xyz1234abcd)
champs[0]=xyz1234abcd
champs[1]=xyz
champs[2]=1234
champs[3]=abcd

Résultats(/^(.*?)(\d+)(.*?)$/,12 34)
champs[0]=12 34
champs[1]=
champs[2]=12
champs[3]= 34

Résultats(/^(.*?)(\d+)(.*?)$/,abcd)
La chaîne [abcd] ne correspond pas au modèle [/^(.*?)(\d+)(.*?)$/]

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,10/05/97)
champs[0]=10/05/97
champs[1]=10
champs[2]=05
champs[3]=97

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,  04/04/01  )
champs[0]=  04/04/01  
champs[1]=04
champs[2]=04
champs[3]=01

Résultats(/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/,5/1/01)
La chaîne [5/1/01] ne correspond pas au modèle [/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/]

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,187.8)
champs[0]=187.8
champs[1]=
champs[2]=187.8

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,-0.6)
champs[0]=-0.6
champs[1]=-
champs[2]=0.6

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4)
champs[0]=4
champs[1]=
champs[2]=4

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,.6)
champs[0]=.6
champs[1]=
champs[2]=.6

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/,4.)
champs[0]=4.
champs[1]=
champs[2]=4.

Résultats(/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/, + 4)
champs[0]= + 4
champs[1]=+
champs[2]=4

Opmerkingen

  • Hier gebruiken we reguliere expressies om de verschillende velden uit een tekenreeks te halen. Met reguliere expressies kunnen we de beperkingen van de functie implode omzeilen. Het principe is om een tekenreeks te vergelijken met een andere tekenreeks, genaamd modèle, met behulp van de functie preg_match:

$correspond = preg_match($modèle, $chaîne, $champs);

De functie preg_match retourneert een booleaanse waarde TRUE als modèle in chaîne kan worden gevonden. Zo ja, dan vertegenwoordigt $champs[0] de subreeks die overeenkomt met het sjabloon. Als modèle bovendien submodellen tussen haakjes bevat, is $champs[1] het deel van $chaîne dat overeenkomt met het eerste submodel, $champs[2] is het deel van $chaîne dat overeenkomt met het tweede subpatroon, enzovoort…

Laten we het eerste voorbeeld eens bekijken. Het patroon wordt gedefinieerd in regel 10: het verwijst naar een reeks van één of meer (+) cijfers (\d) die op willekeurige plaatsen in een tekenreeks voorkomen. Daarnaast definieert het patroon een subpatroon dat tussen haakjes staat;

  • regel 12: het patroon /(\d+)/ (een reeks van één of meer cijfers op een willekeurige plaats in de tekenreeks) wordt vergeleken met de tekenreeks "xyz1234abcd". We zien dat de subreeks 1234 overeenkomt met het patroon. We krijgen dus $champs[0], wat gelijk is aan "1234". Bovendien bevat het patroon subpatronen tussen haakjes. We krijgen dan $champs[1] = "1234";
  • regel 13: het patroon /(\d+)/ wordt vergeleken met de tekenreeks "12 34". We zien dat de deelreeksen 12 en 34 aan het patroon voldoen. De vergelijking stopt bij de eerste deelreeks die aan het patroon voldoet. We krijgen dus $champs[0]=12 en $champs[1]=12 ;
  • regel 14: het patroon /(\d+)/ wordt vergeleken met de tekenreeks "abcd". Er wordt geen overeenkomst gevonden;

Laten we de patronen die verderop in de code worden gebruikt eens toelichten:


$modèle = "/^(.*?)(\d+)(.*?)$/";

komt overeen met het begin van de tekenreeks (^), gevolgd door 0 of meer (*) willekeurige tekens (.), vervolgens 1 of meer (+) cijfers, en daarna opnieuw 0 of meer (*) willekeurige tekens (.). Het patroon (.*) staat voor 0 of meer willekeurige tekens. Zo'n patroon komt overeen met elke willekeurige tekenreeks. Het patroon /^(.*)(\d+)(.*)$/ zal dus nooit worden gevonden, omdat het eerste subpatroon (.*) de hele tekenreeks opneemt. Het patroon (.*?)(\d+) staat daarentegen voor 0 of meer willekeurige tekens tot aan het volgende subpatroon (?), in dit geval \d+. De cijfers worden nu dus niet meer door het patroon (.*) opgeslokt. Het bovenstaande patroon komt dus overeen met [début de chaîne (^), une suite de caractères quelconques (.*?), une suite d'un ou plusieurs chiffres (\d+), une suite de caractères quelconques (.*?), la fin de la chaîne ($)].


$modèle = "/^\s*(\d\d)\/(\d\d)\/(\d\d)\s*$/";

komt overeen met [début de chaîne (^), 2 chiffres (\d\d), le caractère / (\/), 2 chiffres, /, 2 chiffres, une suite de 0 ou plusieurs espaces (\s*), la fin de chaîne ($)].


$modèle = "/^\s*([+|-]?)\s*(\d+\.\d*|\.\d+|\d+)\s*/";

komt overeen met het begin van de tekenreeks (^), 0 of meer spaties (\s*), een teken + of - [+|-] dat 0 of 1 keer voorkomt (?), een reeks van 0 of meer spaties (\s*), 1 of meer cijfers gevolgd door een decimaalteken gevolgd door nul of meer cijfers (\d+\.\d*) of (|) een decimaalteken (\.) gevolgd door een of meer cijfers (\d+) of (|) een of meer cijfers (\d+), een reeks van 0 of meer spaties (\s*)].

Opmerking: de term [espace] in reguliere expressies verwijst naar een reeks tekens: spatie, regeleinde \n, tab \t, carriage return \r, pagina-einde \f…

3.8. De functies

3.8.1. Wijze van doorgeven van parameters

Het script [base-12.php] is als volgt:


<?php

// manier waarop parameters aan een functie worden doorgegeven
// strikte naleving van het type van de parameters
declare(strict_types=1);

function f(int &$i, int $j): void {
  // $i wordt door verwijzing verkregen
  // $j wordt door waarde doorgegeven
  $i++;
  $j++;
  print "f[i,j]=[$i,$j]\n";
}

// tests
$i = 0;
$j = 0;
// $i en $j worden doorgegeven aan de functie f
f($i, $j);
print "test[i,j]=[$i,$j]\n";

Resultaten:

f[i,j]=[1,1]
test[i,j]=[1,0]

Opmerkingen

De bovenstaande code toont de twee manieren waarop parameters aan een functie kunnen worden doorgegeven. Laten we het volgende voorbeeld eens bekijken:

1
2
3
4
5
6
7
function f(&$a,$b){

}

// hoofdprogramma
$i=10; $j=20;
f($i,$j);
  • regel 1: definieert de formele parameters $a en $b van de functie f. Deze functie verwerkt deze twee formele parameters en retourneert een resultaat;
  • regel 7: aanroep van de functie f met twee effectieve parameters $i en $j. De koppelingen tussen de formele parameters ($a, $b) en de effectieve parameters ($i, $j) worden gedefinieerd door de regels 1 en 7:
  • &$a: het teken & geeft aan dat de formele parameter $a de waarde krijgt van het adres van de effectieve parameter $i. Met andere woorden: $a en $i zijn twee verwijzingen naar dezelfde geheugenlocatie. Het bewerken van de formele parameter $a komt neer op het bewerken van de effectieve parameter $i. Dit blijkt uit de uitvoering van de code. Deze overdrachtswijze is geschikt voor uitvoerparameters en omvangrijke gegevens, zoals arrays en woordenboeken. Deze overdrachtswijze wordt ‘overdracht via verwijzing’ genoemd.
  • $b: de formele parameter $b krijgt de waarde van de effectieve parameter $j. Dit is een overdracht per waarde. De formele en effectieve parameters zijn twee verschillende variabelen. Het bewerken van de formele parameter $b heeft geen invloed op de effectieve parameter $j. Dit blijkt uit de uitvoering van de code. Deze overdrachtswijze is geschikt voor invoerparameters.
  • Neem bijvoorbeeld de functie échange, die twee formele parameters $a en $b accepteert. De functie wisselt de waarden van deze twee parameters om. Bij een aanroep met parameterwisseling ($i,$j) verwacht de aanroepende code dus dat de waarden van de twee daadwerkelijke parameters worden omgewisseld. Het zijn dus uitgangsparameters (ze worden gewijzigd). We schrijven dan:
function échange(&$a,&$b){.}

Het volgende script [base-13.php] toont nog enkele voorbeelden:


<?php

// typen in strikte modus
// declare(strict_types = 1);

// wijze van parameteroverdracht

function f(&$i, $j) {
  // $i wordt door verwijzing doorgegeven
  // $j wordt door waarde doorgegeven
  $i++;
  $j++;
  print "f[i,j]=[$i,$j]\n";
}

function g(int &$i, int $j) : void {
  // $i wordt via referentie doorgegeven
  // $j wordt verkregen via waarde
  $i++;
  $j++;
  print "g[i,j]=[$i,$j]\n";
}

// tests
$i = 0;
$j = 0;
// $i en $j worden doorgegeven aan de functie f
f($i, $j);
print "test[i,j]=[$i,$j]\n";
// $i en $j worden doorgegeven aan de functie g
g($i, $j);
print "test[i,j]=[$i,$j]\n";
// er worden onjuiste parameters doorgegeven aan f
$a=5.3;
$b=6.2;
f($a, $b);
print "test[a,b]=[$a,$b]\n";
// er worden onjuiste parameters doorgegeven aan f
$a=5.3;
$b=6.2;
g($a, $b);
print "test[a,b]=[$a,$b]\n";

Opmerkingen

  • regels 8-14: de functie f die in de vorige paragraaf is besproken, maar de parameters zijn niet getypeerd;
  • regels 16-22: de functie g doet hetzelfde als de functie f, maar we specificeren het type van de verwachte parameters – dit is een nieuwigheid PHP 7. We verwachten twee parameters van het type int. We willen zien wat er gebeurt wanneer de daadwerkelijk aan de functie doorgegeven parameter niet het type heeft dat de functie verwacht;
  • regels 25-26: $i en $j zijn twee gehele getallen;
  • regels 28-29: aanroep van de functie f met parameters van het verwachte type;
  • regels 31-32: aanroep van de functie g met parameters van het verwachte type;
  • regels 34-35: de variabelen $a en $b zijn van het type float;
  • regels 36-37: aanroep van de functie f met parameters die niet van het verwachte type zijn;
  • regels 41-42: aanroep van de functie g met parameters die niet van het verwachte type zijn;

Resultaten

1
2
3
4
5
6
7
8
f[i,j]=[1,1]
test[i,j]=[1,0]
g[i,j]=[2,1]
test[i,j]=[2,0]
f[i,j]=[6.3,7.2]
test[a,b]=[6.3,6.2]
g[i,j]=[6,7]
test[a,b]=[6,6.2]
  • uit de regels 5-6 blijkt dat de functie f de twee parameters van het type float heeft geaccepteerd en ermee heeft gewerkt;
  • uit de regels 7-8 blijkt dat de functie g de twee parameters van het type float heeft geaccepteerd, maar deze heeft omgezet naar het type int (regel 7);

Laten we nu regel 4 uitcommentariëren:

declare(strict_types = 1);

Deze instructie geeft aan dat de typen van de formele parameters moeten worden gerespecteerd. Als dat niet het geval is, wordt er een fout gemeld. De resultaten van de uitvoering worden dan:

f[i,j]=[1,1]
test[i,j]=[1,0]
g[i,j]=[2,1]
test[i,j]=[2,0]
f[i,j]=[6.3,7.2]
test[a,b]=[6.3,6.2]

Fatal error: Uncaught TypeError: Argument 1 passed to g() must be of the type integer, float given, called in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php on line 40 and defined in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php:15
Stack trace:
#0 C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php(40): g(5.3, 6.2)
#1 {main}
  thrown in C:\Data\st-2019\dev\php7\php5-exemples\exemples\exemple_111.php on line 15
  • regels 9-10: de interpreter PHP 7 heeft een uitzondering gegenereerd om aan te geven dat de eerste parameter die aan de functie g werd doorgegeven, niet het juiste type had. Het wordt aanbevolen om, waar mogelijk, strikt te zijn met betrekking tot de typen van de parameters, om fouten bij het aanroepen van functies op te sporen;

3.8.2. Resultaten die door een functie worden geretourneerd

Het script [base-15.php] is als volgt:


<?php

// typen in strikte modus
declare(strict_types=1);

// door een functie geretourneerde resultaten
// een functie kan meerdere waarden in een array retourneren
list($res1, $res2, $res3) = f1(10);
print "[$res1,$res2,$res3]\n";
$res = f1(10);
for ($i = 0; $i < count($res); $i++) {
  print "f1 : res[$i]=$res[$i]\n";
}

// een functie kan een object retourneren
$res = f2(10);
print "f2 : [$res->res1,$res->res2,$res->res3]\n";
// wat voor soort object?
print "nature de l'objet : ";
var_dump($res);
print "\n";

// we doen hetzelfde met de functie f3
$res = f3(10);
print "f3 : [$res->res1,$res->res2,$res->res3]\n";
// Wat voor soort object?
print "nature de l'objet : ";
var_dump($res);
print "\n";

// einde
exit;

// functie f1
function f1(int $valeur): array {
  // levert een array op ($valeur+1,$valeur+2,$valeur+3)
  return array($valeur + 1, $valeur + 2, $valeur + 3);
}

// functie f2
function f2(int $valeur): object {
  // geeft een object terug ($valeur+1,$valeur+2,$valeur+3)
  $res->res1 = $valeur + 1;
  $res->res2 = $valeur + 2;
  $res->res3 = $valeur + 3;
  // geeft het object terug
  return $res;
}

// functie f3 – doet hetzelfde als functie f2
function f3(int $valeur): object {
  // geeft een object terug ($valeur+1,$valeur+2,$valeur+3)
  $res = new stdclass();
  $res->res1 = $valeur + 1;
  $res->res2 = $valeur + 2;
  $res->res3 = $valeur + 3;
  // geeft het object terug
  return $res;
}

Resultaten


[11,12,13]
f1 : res[0]=11
f1 : res[1]=12
f1 : res[2]=13

Warning: Creating default object from empty value in C:\Data\st-2019\dev\php7\php5-exemples\exemples\bases\base-15.php on line 43
f2 : [11,12,13]
nature de l'objet : object(stdClass)#1 (3) {
  ["res1"]=>
  int(11)
  ["res2"]=>
  int(12)
  ["res3"]=>
  int(13)
}

f3 : [11,12,13]
nature de l'objet : object(stdClass)#2 (3) {
  ["res1"]=>
  int(11)
  ["res2"]=>
  int(12)
  ["res3"]=>
  int(13)
}

Opmerkingen

  • het vorige programma laat zien dat een functie PHP een reeks resultaten kan opleveren in plaats van één enkel resultaat, in de vorm van een array of een object. Het begrip 'object' wordt iets verderop toegelicht;
  • regels 35-38: de functie f1 retourneert meerdere waarden in de vorm van een array;
  • regels 41-48: de functie f2 retourneert meerdere waarden in de vorm van een object;
  • regels 51-59: de functie f3 is identiek aan de functie f2, behalve dat ze expliciet een object aanmaakt, regel 53;
  • regel 6 van de resultaten geeft een waarschuwing (warning) weer die aangeeft dat PHP gedwongen was om een standaardobject aan te maken op regel 43 van de code, d.w.z. bij het gebruik van de notatie [$res→res1]. De functie var_dump op regel 20 van de code geeft toegang tot het type van het object en de inhoud ervan. In de resultaten zien we dat:
    • regel 8: het standaard aangemaakte object is van het type stdClass;
    • regels 9-10: de eigenschap res1 is van het type entier en heeft de waarde 11;
    • enz…
    • om de waarschuwing in regel 6 van de resultaten te vermijden, maken we expliciet, in regel 53 van de functie f3, een object van het type stdClass aan;

3.9. De tekstbestanden

Het script [bases-16.php] is als volgt:


<?php

// strikte naleving van het type van de functieparameters
declare (strict_types=1);

// sequentiële verwerking van een tekstbestand
// dit is een verzameling regels in de vorm login:pwd:uid:gid:infos:dir:shell
// elke regel wordt in een woordenboek opgeslagen in de vorm login => uid:gid:infos:dir:shell
// de bestandsnaam wordt vastgelegd
$INFOS = "infos.txt";
// het bestand wordt geopend om te worden aangemaakt
if (!$fic = fopen($INFOS, "w")) {
  print "Erreur d'ouverture du fichier $INFOS en écriture\n";
  exit;
}
// er wordt willekeurige inhoud gegenereerd
for ($i = 0; $i < 100; $i++) {
  fputs($fic, "login$i:pwd$i:uid$i:gid$i:infos$i:dir$i:shell$i\n");
}
// het bestand wordt gesloten
fclose($fic);

// we maken er gebruik van – fgets behoudt de regeleinde-markering
// hierdoor wordt voorkomen dat er een lege tekenreeks wordt opgehaald bij het lezen van een lege regel
// het bestand wordt geopend voor lezen
if (!$fic = fopen($INFOS, "r")) {
  print "Erreur d'ouverture du fichier $INFOS en lecture\n";
  exit;
}

// de regels zijn korter dan 1000 tekens
// het lezen van de regel stopt bij de regeleinde-markering
// of bij het einde van het bestand
while ($ligne = fgets($fic, 1000)) {
  // het einde-van-regel-teken wordt verwijderd, indien aanwezig
  $ligne = cutNewLineChar($ligne);
  // we plaatsen de regel in een tabel
  $infos = explode(":", $ligne);
  // we halen de login op
  $login = array_shift($infos);
  // het wachtwoord wordt genegeerd
  array_shift($infos);
  // we maken een vermelding aan in het woordenboek
  $dico[$login] = $infos;
}
// we sluiten het
fclose($fic);

// het woordenboek wordt doorzocht
afficheInfos($dico, "login10");
afficheInfos($dico, "X");

// einde
exit;

// --------------------------------------------------------------------------
function afficheInfos(array $dico, string $clé): void {
  // de waarde weergeven die bij de sleutel in het woordenboek $dico hoort, indien deze bestaat
  if (isset($dico[$clé])) {
    // waarde bestaat – is het een array?
    $valeur = $dico[$clé];
    if (is_array($valeur)) {
      print "[$clé," . join(":", $valeur) . "]\n";
    } else {
      // $valeur is geen array
      print "[$clé,$valeur]\n";
    }
  } else {
    // $clé is geen sleutel in het woordenboek $dico
    print "la clé [$clé] n'existe pas\n";
  }
}

// --------------------------------------------------------------------------
function cutNewLinechar(string $ligne): string {
  // de regeleinde-markering van $ligne wordt verwijderd, indien deze bestaat
  $L = strlen($ligne);  // regellengte
  while (substr($ligne, $L - 1, 1) == "\n" or substr($ligne, $L - 1, 1) == "\r") {
    $ligne = substr($ligne, 0, $L - 1);
    $L--;
  }
  // einde
  return($ligne);
}

Het bestand infos.txt:

1
2
3
4
5
6
login0:pwd0:uid0:gid0:infos0:dir0:shell0
login1:pwd1:uid1:gid1:infos1:dir1:shell1
login2:pwd2:uid2:gid2:infos2:dir2:shell2
login98:pwd98:uid98:gid98:infos98:dir98:shell98
login99:pwd99:uid99:gid99:infos99:dir99:shell99

De resultaten:


[login10,uid10:gid10:infos10:dir10:shell10]
la clé [X] n'existe pas

Opmerkingen

  • regel 12: fopen(nom_fichier,"w") opent het bestand nom_fichier in schrijfmodus (w=write). Als het bestand niet bestaat, wordt het aangemaakt. Als het bestaat, wordt het leeggemaakt. Als het aanmaken mislukt, retourneert fopen de waarde false. In de instructie if (!$fic = fopen($INFOS, "w")) {…} vinden twee opeenvolgende bewerkingen plaats: 1) $fic = fopen(..) 2) if( ! $fic) {…} ;
  • regel 18: fputs($fic,$chaîne) schrijft chaîne naar het bestand $fic. $chaine wordt geschreven met het regeleinde-teken \n erachter;
  • regel 21: fclose($fic) sluit het bestand $fic;
  • regel 26: fopen(nom_fichier,"r") opent het bestand nom_fichier in leesmodus (r=read). Als het openen mislukt (bijvoorbeeld omdat het bestand niet bestaat), retourneert fopen de waarde false;
  • regel 34: fgets($fic, 1000) leest de volgende regel uit het bestand, met een limiet van 1000 tekens. In de while-constructie ($ligne = fgets($fic, 1000)) {…} vinden twee opeenvolgende bewerkingen plaats: 1) $ligne = fgets(…) 2) while ( ! $ligne). Nadat het laatste teken van het bestand is gelezen, retourneert de functie fgets de waarde false en stopt de lus while. De functie fgets probeert hier maximaal 1000 tekens te lezen, maar stopt zodra een regeleinde wordt aangetroffen. Aangezien alle regels hier minder dan 1000 tekens bevatten, leest [fgets] een regel tekst, inclusief het regeleinde. De functie cutNewLineChar in de regels 75-84 verwijdert eventuele regeleinde-tekens;
  • regel 77: de functie strlen($chaîne) geeft het aantal tekens van $chaîne weer;
  • regel 78: de functie substr($ligne, $position, $taille) levert $taille tekens op uit $ligne, beginnend bij teken nr. $position, waarbij het eerste teken nummer 0 heeft. Op Windows-computers is het teken voor het einde van een regel "\r\n". Op Unix-computers is dit de tekenreeks "\n";
  • regel 40: de functie array_shift($tableau) verwijdert het eerste element uit $tableau en retourneert dit als resultaat. Het door array_shift geretourneerde resultaat wordt hier buiten beschouwing gelaten;
  • regel 62: de functie is_array($variable) retourneert true als $variable een array is, en anders false;
  • regel 63: de functie join doet hetzelfde als de functie implode die we al eerder zijn tegengekomen;

3.10. Codering / decodering jSON

Image

De codering / decodering jSON (JavaScript Object Notation) is iets wat we intensief zullen gebruiken in de oefening die als rode draad door het document loopt. De scripts [json-01.php, json-02.php, json-03.php] leggen uit wat je moet weten voor het vervolg.

Het script [json-01.php] luidt als volgt:


<?php

$array1 = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34];
// JSON-codering van de array array1 met geëscape Unicode-tekens
print "encodage json du tableau array1 avec caractères Unicode échappés\n";
$json1 = json_encode($array1);
print "json1=$json1\n";
// JSON-codering van de array array1 met niet-geëscape Unicode-tekens
print "encodage json du tableau array1 avec caractères Unicode non échappés\n";
$json2 = json_encode($array1, JSON_UNESCAPED_UNICODE);
print "json2=$json2\n";
// decodering van jSON in associatieve array
print "décodage jSON de json2 dans tableau associatif\n";
$array2 = json_decode($json2, true);
var_dump($array2);
foreach ($array2 as $key => $value) {
  print "$key:$value\n";
}
// decodering van jSON in een object
print "décodage jSON de json2 dans objet stdClass\n";
$array2 = json_decode($json2);
var_dump($array2);
print "prénom=$array2->prénom\n";
print "nom=$array2->nom\n";
print "âge=$array2->âge\n";

Resultaten

encodage json du tableau array1 avec caractères Unicode échappés
json1={"nom":"s\u00e9l\u00e9n\u00e9","pr\u00e9nom":"b\u00e9n\u00e9dicte","\u00e2ge":34}
encodage json du tableau array1 avec caractères Unicode non échappés
json2={"nom":"séléné","prénom":"bénédicte","âge":34}
décodage jSON de json2 dans tableau associatif
array(3) {
  ["nom"]=>
  string(9) "séléné"
  ["prénom"]=>
  string(11) "bénédicte"
  ["âge"]=>
  int(34)
}
nom:séléné
prénom:bénédicte
âge:34
décodage jSON de json2 dans objet stdClass
object(stdClass)#1 (3) {
  ["nom"]=>
  string(9) "séléné"
  ["prénom"]=>
  string(11) "bénédicte"
  ["âge"]=>
  int(34)
}
prénom=bénédicte
nom=séléné
âge=34

Opmerkingen

  • regel 6 van de code: de functie [json_encode] zet haar parameter om in de tekenreeks jSON;
  • regel 2 van de resultaten: de gegenereerde tekenreeks jSON. De Unicode-tekens éâ zijn vervangen door hun Unicode-code die begint met \u;
  • regel 10 van de code: we doen hetzelfde nogmaals, maar vragen deze keer om de Unicode-tekens ongewijzigd te laten;
  • regel 4 van de resultaten: de resulterende tekenreeks jSON. Deze is veel beter leesbaar;
  • regels 14-18 van de code: we voeren de omgekeerde bewerking uit. We zetten de tekenreeks jSON om in een associatieve array;
  • regels 6-13 van de resultaten: we zien dat we een associatief array hebben verkregen;
  • regels 19-25 van de code: we zetten een tekenreeks jSON om in een object van het type [stdClass];
  • regels 18-25 van de resultaten: we zien dat we een object van het type [stdClass] hebben opgehaald;
  • regels 23-25 van de code: het attribuut A van een object O wordt aangeduid als [O→A];

We kunnen tabellen met meerdere niveaus coderen in jSON, zoals te zien is in het volgende script [json-02.php]:


<?php

$array = ["nom" => "séléné", "prénom" => "bénédicte", "âge" => 34,
  "mari" => ["nom" => "icariù", "prénom" => "ignacio", "âge" => 35],
  "enfants" => [
    ["prénom" => "angèle", "age" => 8],
    ["prénom" => "andré", "age" => 2],
  ]];
// codering van de meerlaagse array in jSON
print "encodage jSON d'un tableau à plusieurs niveaux\n";
$json = json_encode($array, JSON_UNESCAPED_UNICODE);
print "json=$json\n";

Resultaten


encodage jSON d'un tableau à plusieurs niveaux
json={"nom":"séléné","prénom":"bénédicte","âge":34,"mari":{"nom":"icariù","prénom":"ignacio","âge":35},"enfants":[{"prénom":"angèle","age":8},{"prénom":"andré","age":2}]}

Opmerkingen

In de string jSON:

  • niet-associatieve arrays worden tussen vierkante haakjes [] geplaatst;
  • associatieve arrays worden tussen accolades {} geplaatst;

Het script [json-03.php] laat zien hoe het volgende bestand jSON [famille.json] kan worden gebruikt:


{
    "épouse": {
        "nom": "séléné",
        "prénom": "bénédicte",
        "âge": 34
    },
    "mari": {
        "nom": "icariù",
        "prénom": "ignacio",
        "âge": 35
    },
    "enfants": [
        {
            "prénom": "angèle",
            "age": 8
        },
        {
            "prénom": "andré",
            "age": 2
        }
    ]
}

Het script [json-03.php] is als volgt:


<?php

// het bestand jSON lezen
$json = file_get_contents("famille.json");
// JSON decoderen naar object
$famille1 = json_decode($json);
print "----famille1\n";
var_dump($famille1);
// JSON decoderen naar associatieve array
print "----famille2\n";
$famille2 = json_decode($json, true);
var_dump($famille2);

Opmerkingen

  • regel 4: de functie [file_get_contents] leest de inhoud van het bestand met de naam [famille.json] en slaat deze op in de variabele [$json];
  • de variabele wordt vervolgens gedecodeerd tot een object (regels 5-8) en tot een associatieve array (regels 9-12);

Resultaten


----famille1
object(stdClass)#2 (3) {
  ["épouse"]=>
  object(stdClass)#1 (3) {
    ["nom"]=>
    string(9) "séléné"
    ["prénom"]=>
    string(11) "bénédicte"
    ["âge"]=>
    int(34)
  }
  ["mari"]=>
  object(stdClass)#3 (3) {
    ["nom"]=>
    string(7) "icariù"
    ["prénom"]=>
    string(7) "ignacio"
    ["âge"]=>
    int(35)
  }
  ["enfants"]=>
  array(2) {
    [0]=>
    object(stdClass)#4 (2) {
      ["prénom"]=>
      string(7) "angèle"
      ["age"]=>
      int(8)
    }
    [1]=>
    object(stdClass)#5 (2) {
      ["prénom"]=>
      string(6) "andré"
      ["age"]=>
      int(2)
    }
  }
}
----famille2
array(3) {
  ["épouse"]=>
  array(3) {
    ["nom"]=>
    string(9) "séléné"
    ["prénom"]=>
    string(11) "bénédicte"
    ["âge"]=>
    int(34)
  }
  ["mari"]=>
  array(3) {
    ["nom"]=>
    string(7) "icariù"
    ["prénom"]=>
    string(7) "ignacio"
    ["âge"]=>
    int(35)
  }
  ["enfants"]=>
  array(2) {
    [0]=>
    array(2) {
      ["prénom"]=>
      string(7) "angèle"
      ["age"]=>
      int(8)
    }
    [1]=>
    array(2) {
      ["prénom"]=>
      string(6) "andré"
      ["age"]=>
      int(2)
    }
  }
}

Opmerkingen

  • regels 1-38: het object dat is verkregen door het decoderen van het bestand jSON [famille.json];
  • regels 39-76: de associatieve tabel die is verkregen door het decoderen van het bestand jSON [famille.json];