PHP 7 – die neuen Funktionen im Überblick – Teil 2


Expectations

Mit Expactations lassen sich Stellen im Code markieren, die eigentlich nicht erreicht werden sollen, aber falls doch, eine Nachricht in der Produktionsumgebung hinterlassen könnnen, um anderen Programmierern beim Debuggen und verstehen des Codes zu helfen. Der Parameter expression wird ausgewertet und bei einem false-Wert wird eine AssertionException geworfen.

Definition:

void assert (mixed $expression [, mixed $message]);

Die php.ini Konfigurationsvariable zend.assertions kann 3 Wert annehmen

  • 1 = generate and execute code (development mode)
  • 0 = generate code and jump around at it at runtime
  • -1 = don’t generate any code (zero-cost, production mode)

Die php.ini Konfigurationsvariable  assert.exception has three values:

  • 1 = Exception werfen, wenn die expression den Wert false hat
  • 0 = keine Exception werfen, wenn die expression den Wert false hat

Beispiel:

ini_set('zend.assertion', '1'); //in development mode
ini_set('assert.exception', '1'); //in development mode
public function method() {
    for (/*...*/) {

        if (/* ... */)
           return true;
    }
    assert(false, 'Error, something went wrong');
}

Die Exception wird hier nur geworfen, wenn die php.ini Variable assert.exception gesetzt ist (bspw. in der Test-Umgebung). Dadurch wird vermieden, dass eine perfomanceintensive Exception an der Stelle geworfen wird in der Live-Umgebung.

Beispiel 2:

Dieser Code wirft keine Exception:

ini_set('assert.exception', '0');
ini_set('zend.assertions', '0');

assert(false, 'Some error message');

Dieser dagegen schon

ini_set('assert.exception', '1');
ini_set('zend.assertions', '1');

assert(false, 'Some error message');
Fatal error: Some error message

Gruppierte use-Syntax

Use-Statements mit gleichem parent Namespace können leichter notiert und übersichtlich zusammengefasst werden:

// Pre PHP 7 code
use some\namespace\ClassA;
use some\namespace\ClassB;
use some\namespace\ClassC as C;

use function some\namespace\fn_a;
use function some\namespace\fn_b;
use function some\namespace\fn_c;

use const some\namespace\ConstA;
use const some\namespace\ConstB;
use const some\namespace\ConstC;

// PHP 7+ code
use some\namespace\{ClassA, ClassB, ClassC as C};
use function some\namespace\{fn_a, fn_b, fn_c};
use const some\namespace\{ConstA, ConstB, ConstC};

 Der Generator Syntax

Eine Generatorfunktion sieht genau so aus wie eine normale Funktion mit der Ausnahme, dass ein Generator statt eines Wertes so viele Werte wie nötig zurückgibt.

Das Herz einer Generatorfunktion ist das yield-Schlüsselwort. In seiner einfachsten Form sieht das yield-Schlüsselwort wie eine return-Anweisung aus, ausser dass die Ausführung mit der Rückgabe nicht beendet wird, sondern yield stattdessen bei der Schleife über den Generator einen Wert für den Code bereitstellt, solange die Ausführung der Generatorfunktion anhält.

Ein Generator kann keine Werte zurückgeben: macht man dies, wird ein Kompilierungsfehler zurückgegeben. Eine leere return-Anweisung ist eine gültige Syntax innerhalb eines Generators und wird den Generator beenden.

Quelle: php.net

 function generiere_eins_bis_drei() {
    for ($i = 1; $i <= 3; $i++) {
        // Hinweis: $i bleibt zwischen den yields erhalten.
        yield $i;
    }
}

$generator = generiere_eins_bis_drei();
foreach ($generator as $wert) {
    echo "$wert\n";
}

//Ouput:
1
2
3

Die Intdiv Funkton – Division und ganzzahliges Runden in einem

var_dump(intdiv(10, 3)); // int(3)

Session Tuning

Die altbekannte session_start() function kann jetzt mit 3 neuen Parameter für mehr Performance getunt werden:

session_start([ 'read_and_close' => true, ]);

Die Session wird sofort nach dem lesen wieder geschlossen, so kann am schnellsten bei sich blockierenden Aufrufen der Session gelesen werden.

Es ist zu beachten, dass es dadurch zu Inkonsistenzen bei konkurrierenden Schreibversuchen auf die Session kommen kann wenn Request A und B lessen die Session nacheinander und speichern nacheinander neue Werte in die Session, dabei überschreibt der letzte Update-Request die Änderungen des ersten Request.

ini_set(session.lazy_write)

Ist per default aktiviert, die Session wird nur überspeichert, wenn sie sich auch geändert hat. Macht Sinn, wenn die Session-Daten nicht von konkurrierenden Requests verändert werden können und nicht sequentiell geschrieben werden müssen.

Damit kann man erreichen, dass sich überlappende Zugriffe (z.B: durch asynchrone Requests) von demselben User blockieren beim Lesen und Schreiben der Session.

Die neue preg_replace_callback_array() Funktion

Der Syntax der alten Funktion preg_replace_callback() führte zu schwer lesbarem, überflüssigem Code und wird durch die neue preg_replace_callback_array() verbessert.

    $tokenStream = [];

    $input = '$a = 3; // variable initialisation';

// Pre PHP 7 code
    preg_replace_callback(
        [
            '~\$[a-z_][a-z\d_]*~i',
            '~=~',
            '~[\d]+~',
            '~;~',
            '~//.*~'
        ],
        function ($match) use (&$tokenStream) {
            if (strpos($match[0], '$') === 0) {
                $tokenStream[] = ['T_VARIABLE', $match[0]];
            } elseif (strpos($match[0], '=') === 0) {
                $tokenStream[] = ['T_ASSIGN', $match[0]];
            } elseif (ctype_digit($match[0])) {
                $tokenStream[] = ['T_NUM', $match[0]];
            } elseif (strpos($match[0], ';') === 0) {
                $tokenStream[] = ['T_TERMINATE_STMT', $match[0]];
            } elseif (strpos($match[0], '//') === 0) {
                $tokenStream[] = ['T_COMMENT', $match[0]];
            }
        },
        $input
    );

// PHP 7+ code
    preg_replace_callback_array(
        [
            '~\$[a-z_][a-z\d_]*~i' => function ($match) use (&$tokenStream) {
                $tokenStream[] = ['T_VARIABLE', $match[0]];
            },
            '~=~' => function ($match) use (&$tokenStream) {
                $tokenStream[] = ['T_ASSIGN', $match[0]];
            },
            '~[\d]+~' => function ($match) use (&$tokenStream) {
                $tokenStream[] = ['T_NUM', $match[0]];
            },
            '~;~' => function ($match) use (&$tokenStream) {
                $tokenStream[] = ['T_TERMINATE_STMT', $match[0]];
            },
            '~//.*~' => function ($match) use (&$tokenStream) {
                $tokenStream[] = ['T_COMMENT', $match[0]];
            }
        ],
        $input
    );
    var_dump($tokenStream);

Ergebnis:

array (size=5)
  0 => 
    array (size=2)
      0 => string 'T_VARIABLE' (length=10)
      1 => string '$a' (length=2)
  1 => 
    array (size=2)
      0 => string 'T_ASSIGN' (length=8)
      1 => string '=' (length=1)
  2 => 
    array (size=2)
      0 => string 'T_NUM' (length=5)
      1 => string '3' (length=1)
  3 => 
    array (size=2)
      0 => string 'T_TERMINATE_STMT' (length=16)
      1 => string ';' (length=1)
  4 => 
    array (size=2)
      0 => string 'T_COMMENT' (length=9)
      1 => string '// variable initialisation' (length=26)

Kryptographisch sichere Zufallszahlen mit random_int()

Definition:

int random_int(int min, int max);

Wenn keine sichere Zufallszahl generiert werden kann, wird eine Exception geworfen.

Folgende Systemfunktionen werden auf den unterschiedlichen Betriebsystemen verwendet:

  • Unter Windows CryptGenRandom()
  • Unter Linux wird der getrandom(2) syscall
  • Auf anderen Plattformen /dev/urandom

Ein Array als Konstante  definieren

 define('ALLOWED_FILE_TYPES', ['jpg', 'jpeg', 'gif', 'png']);

Verwendung von global reservierten Bezeichnern

Global reservierte Bezeichner können jetzt als Klassenvariablen oder Methoden verwendet werden:

// 'new', 'private', and 'for' were previously unusable
Project::new('Project Name')->private()->for('purpose here');

 

Zurück zu PHP 7 – die neuen Funktionen im Überblick – Teil 1