assert

(PHP 4, PHP 5, PHP 7, PHP 8)

assertÜberprüft eine Assertion (Zusicherung)

Beschreibung

assert(mixed $assertion, Throwable|string|null $description = null): bool

assert() ist keine Funktion, sondern ein Sprachkonstrukt, das die Definition von Expectations (Annahmen) ermöglicht: Zusicherungen, die in Entwicklungs- und Testumgebungen wirken, aber so optimiert werden, dass sie in Produktionsumgebungen keinen Mehraufwand verursachen.

Zusicherungen sollten nur zur Fehlersuche verwendet werden. So können sie z. B. für Plausibilitätsprüfungen für Vorbedingungen verwendet werden, die immer true sein sollten, und die andernfalls auf Programmierfehler hinweisen. Ein weiterer Anwendungsfall ist, sicherzustellen, dass bestimmte Merkmale wie Funktionen von Erweiterungen oder bestimmte Grenzwerte und Eigenschaften des Systems vorhanden sind.

Da Zusicherungen so konfiguriert werden können, dass sie deaktiviert werden, sollten sie nicht für normale Laufzeitoperationen wie die Überprüfung von Eingabeparametern verwendet werden. Als Faustregel gilt, dass sich der Code auch bei deaktivierter Zusicherungsüberprüfung so verhalten sollte wie erwartet.

assert() prüft, ob die in assertion angegebene Annahme zutrifft. Wenn dies nicht der Fall ist und das Ergebnis somit false ist, werden die entsprechenden Maßnahmen ergriffen, je nachdem wie assert() konfiguriert wurde.

Das Verhalten von assert() wird durch die folgenden INI-Einstellungen bestimmt:

Konfigurationsoptionen für assert
Name Standard Beschreibung Changelog
zend.assertions 1
  • 1: erzeugt Code und führt ihn aus (Entwicklungsmodus).
  • 0: erzeugt Code, aber führt ihn zur Laufzeit nicht aus.
  • -1: erzeugt keinen Code (Produktionsmodus).
 
assert.active true Wenn false, prüft assert() die Annahme nicht und gibt automatisch true zurück.  
assert.callback null Eine benutzerdefinierte Funktion, die aufgerufen wird, wenn eine Zusicherung fehlschlägt. Sie sollte die folgende Signatur haben:
assert_callback(
    string $file,
    int $line,
    null $assertion,
    string $description = ?
): void
Vor PHP 8.0.0 musste die Signatur des Callbacks wie folgt lauten:
assert_callback(
    string $file,
    int $line,
    string $assertion,
    string $description = ?
): void
assert.exception true Wenn true, wird ein AssertionError ausgelöst, wenn die Erwartung nicht erfüllt wird.  
assert.bail false Wenn true, wird die Ausführung des PHP-Skripts gestoppt, wenn die Erwartung nicht erfüllt wird.  
assert.warning true Wenn true, wird eine E_WARNING ausgegeben, wenn die Erwartung nicht erfüllt wird. Diese INI-Einstellung hat keine Auswirkung, wenn assert.exception aktiviert ist.  
Die mit assert. beginnenden Optionen können über assert_options() konfiguriert werden. Allerdings wird dies nicht empfohlen.

Parameter-Liste

assertion

Dies ist ein beliebiger Ausdruck, der einen Wert zurückgibt, der ausgeführt wird und dessen Ergebnis verwendet wird, um anzuzeigen, ob die Zusicherung erfolgreich war oder fehlschlug.

Warnung

Vor PHP 8.0.0 wurde assertion, wenn es vom Typ string war, als PHP-Code interpretiert und über eval() ausgeführt. Diese Zeichenkette wurde dann als drittes Argument an den Callback übergeben. Dieses Verhalten war in PHP 7.2.0 MISSBILLIGT, und wurde in PHP 8.0.0 ENTFERNT.

description

Wenn description eine Instanz von Throwable ist, wird sie nur ausgelöst, wenn die assertion ausgeführt wird und fehlschlägt.

Hinweis:

Seit PHP 8.0.0 wird dies durchgeführt bevor ein möglicherweise definierter Zusicherungs-Callback aufgerufen wird.

Hinweis:

Seit PHP 8.0.0 wird das Objekt unabhängig von der Einstellung von assert.exception ausgelöst.

Hinweis:

Seit PHP 8.0.0 hat die Einstellung von assert.bail in diesem Fall keine Wirkung mehr.

Wenn description vom Typ String ist, wird diese Nachricht verwendet, wenn eine Exception oder eine Warnung ausgegeben wird. Eine optionale Beschreibung, die in die Fehlermeldung aufgenommen wird, wenn die assertion fehlschlägt.

description kann weggelassen werden. Die Standardbeschreibung entspricht dem Quellcode für den Aufruf von assert() und wird zur Kompilierzeit erstellt.

Rückgabewerte

false, wenn assertion false ist, anderfalls true.

Changelog

Version Beschreibung
8.0.0 assert() wertet Zeichenketten nicht mehr aus, sondern behandelt sie stattdessen wie jeden anderen Parameter. Anstelle von assert('$a == $b') sollte assert($a == $b) verwendet werden. Die php.ini-Direktive assert.quiet_eval und die Konstante ASSERT_QUIET_EVAL wurden ebenfalls entfernt, da sie keine Auswirkungen mehr haben.
8.0.0 Wenn description eine Instanz von Throwable ist, wird nun ein Objekt ausgelöst, wenn die Zusicherung fehlschlägt, unabhängig vom Wert von assert.exception.
8.0.0 Wenn description eine Instanz von Throwable ist, wird kein Benutzer-Callback aufgerufen, auch wenn er gesetzt ist.
8.0.0 Die Deklaration einer Funktion namens assert() innerhalb eines Namensraums ist nicht mehr erlaubt und führt zu einem Fehler der Stufe E_COMPILE_ERROR.
7.3.0 Die Deklaration einer Funktion namens assert() innerhalb eines Namensraums ist veraltet und gibt nun einen E_DEPRECATED-Hinweis aus.
7.2.0 Die Verwendung eines Strings als assertion wird missbilligt. Dies erzeugt nun einen E_DEPRECATED-Hinweis, wenn sowohl assert.active als auch zend.assertions auf 1 gesetzt sind.

Beispiele

Annahmen

<?php
assert
(true == false);
echo
'Hi!';
?>

Ist zend.assertions auf 0 gesetzt, gibt das obige Beispiel folgendes aus:

Hi!

Ist zend.assertions auf 1 gesetzt und assert.exception auf 0, gibt das obige Beispiel folgendes aus:

Warning: assert(): assert(true == false) failed in - on line 2
Hi!

Ist zend.assertions auf 1 gesetzt und assert.exception auf 1, gibt das obige Beispiel folgendes aus:

Fatal error: Uncaught AssertionError: assert(true == false) in -:2
Stack trace:
#0 -(2): assert(false, 'assert(true == ...')
#1 {main}
  thrown in - on line 2

Beispiel #1 Annahmen mit einer benutzerdefinierten Exception

<?php
class CustomError extends AssertionError {}

assert(true == false, new CustomError('True ist nicht false!'));
echo
'Hi!';
?>

Ist zend.assertions auf 0 gesetzt, gibt das obige Beispiel folgendes aus:

Hi!

Ist zend.assertions auf 1 gesetzt und assert.exception auf 0, gibt das obige Beispiel folgendes aus:

Warning: assert(): CustomError: True ist nicht false! in -:4
Stack trace:
#0 {main} failed in - on line 4
Hi!

Ist zend.assertions auf 1 gesetzt und assert.exception auf 1, gibt das obige Beispiel aus:

Fatal error: Uncaught CustomError: True ist nicht false! in -:4
Stack trace:
#0 {main}
  thrown in - on line 4

Zusicherungen mit ausgewertetem Code (nur PHP 7)

Bei Zusicherungen mit ausgewertetem Code können assert()-Callbacks besonders nützlich sein, da der für die Zusicherung verwendete Code zusammen mit Informationen darüber, wo die Zusicherung durchgeführt wurde, an den Callback übergeben wird.

Beispiel #2 Handhabung einer fehlgeschlagenen Zusicherung mit benutzerdefiniertem Handler

<?php
// Zusicherungen aktivieren und stummschalten
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_QUIET_EVAL, 1);

// Eine Handlerfunktion erzeugen
function my_assert_handler($file, $line, $code)
{
echo
"<hr>Zusicherung fehlgeschlagen:
Datei '
$file'<br />
Zeile '
$line'<br />
Code '
$code'<br /><hr />";
}

// Den Callback definieren
assert_options(ASSERT_CALLBACK, 'my_assert_handler');

// Eine Zusicherung, die fehlschlagen sollte
$array = [];
assert('count($array);');
?>

Das oben gezeigte Beispiel erzeugt mit PHP 7.2 folgende Ausgabe:

Deprecated: assert(): Calling assert() with a string argument is deprecated in test.php on line 21
<hr>Zusicherung fehlgeschlagen:
        Datei 'test.php'<br />
        Zeile '21'<br />
        Code 'count($array);'<br /><hr />

Das oben gezeigte Beispiel erzeugt mit PHP 7.1 folgende Ausgabe:

<hr>Zusicherung fehlgeschlagen:
        Datei 'test.php'<br />
        Zeile '21'<br />
        Code 'count($array);'<br /><hr />

Beispiel #3 Verwendung eines benutzerdefinierten Handlers um eine Beschreibung anzuzeigen

<?php
// Zusicherungen aktivieren und stummschalten
assert_options(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_QUIET_EVAL, 1);

// Eine Handlerfunktion erzeugen
function my_assert_handler($file, $line, $code, $desc = null)
{
echo
"Zusicherung fehlgeschlagen in $file:$line: $code";
if (
$desc) {
echo
": $desc";
}
echo
"\n";
}

// Den Callback definieren
assert_options(ASSERT_CALLBACK, 'my_assert_handler');

// Zusicherungen, die fehlschlagen sollten
assert('2 < 1');
assert('2 < 1', 'Zwei ist kleiner als Eins');
?>

Das oben gezeigte Beispiel erzeugt mit PHP 7.2 folgende Ausgabe:

Deprecated: assert(): Calling assert() with a string argument is deprecated in test.php on line 21
Assertion failed at test.php:21: 2 < 1

Deprecated: assert(): Calling assert() with a string argument is deprecated in test.php on line 22
Assertion failed at test.php:22: 2 < 1: Zwei ist kleiner als Eins

Das oben gezeigte Beispiel erzeugt mit PHP 7.1 folgende Ausgabe:

Zusicherung fehlgeschlagen in test.php:21: 2 < 1
Zusicherung fehlgeschlagen in test.php:22: 2 < 1: Zwei ist kleiner als Eins

Siehe auch

add a note

User Contributed Notes 9 notes

up
26
hodgman at ali dot com dot au
15 years ago
As noted on Wikipedia - "assertions are primarily a development tool, they are often disabled when a program is released to the public." and "Assertions should be used to document logically impossible situations and discover programming errors— if the 'impossible' occurs, then something fundamental is clearly wrong. This is distinct from error handling: most error conditions are possible, although some may be extremely unlikely to occur in practice. Using assertions as a general-purpose error handling mechanism is usually unwise: assertions do not allow for graceful recovery from errors, and an assertion failure will often halt the program's execution abruptly. Assertions also do not display a user-friendly error message."

This means that the advice given by "gk at proliberty dot com" to force assertions to be enabled, even when they have been disabled manually, goes against best practices of only using them as a development tool.
up
4
Tom
4 years ago
When migrating older code to PHP 7.2+, you may get E_DEPRECATED warnings for every call to assert() you ever wrote, urging you to not pass the assertion as a string.

It may be tempting to just run a regular expression across your files to convert all strings within "assert(...)" to statements. But, before you do that, be aware of the following caveat!

For example, this code simply asserts that $input is not empty.

assert('$input;');

This works, because the string passed to assert() is evaluated as a PHP statement and the result cast to Boolean.

If you want to have an equivalent statement that doesn't pass the first parameter as a string, your regular expression should rewrite this statement as:

assert((bool) ($input));

However, this looks a bit bulky and it is tempting to instead opt for the more direct approach to convert the above line to this:

assert($input);

But! This new statement will do one of three things:

1) Looks as if it worked as intended because $input just happens to be Boolean to begin with
2) Throw a parse error if $input is a string (best case)
3) Allow an attacker on a poorly configured server to execute arbitrary PHP-Code (worst case)

The reason is that, even though on PHP 7.2+ a E_DEPRECATED warning is raised, if assert() finds the first parameter to be a string, it will still execute it as PHP-Code, just as if it was called with a string to begin with.

If an attacker finds a way to manipulate the contents of $input, you might end up with a remote code execution vulnerability. So just be extra careful when migrating assertions.
up
6
mail<at>aaron-mueller.de
17 years ago
Here is a simple demonstration of Design By Contract with PHP

<?php

assert_options
(ASSERT_ACTIVE, 1);
assert_options(ASSERT_WARNING, 0);
assert_options(ASSERT_BAIL, 1);
assert_options(ASSERT_CALLBACK, 'dcb_callback');

function
dcb_callback($script, $line, $message) {
echo
"<h1>Condition failed!</h1><br />
Script: <strong>
$script</strong><br />
Line: <strong>
$line</strong><br />
Condition: <br /><pre>
$message</pre>";
}

// Parameters
$a = 5;
$b = 'Simple DCB with PHP';

// Pre-Condition
assert('
is_integer($a) &&
($a > 0) &&
($a < 20) &&

is_string($b) &&
(strlen($b) > 5);
'
);

// Function
function combine($a, $b) {
return
"Kombined: " . $b . $a;
}

$result = combine($a, $b);

// Post-Condition
assert('
is_string($result) &&
(strlen($result) > 0);
'
);

// All right, the Function works fine
var_dump($result);

?>
up
4
Krzysztof &#39;ChanibaL&#39; Bociurko
16 years ago
Note that func_get_args() should be used carefully and never in a string! For example:

<?php
function asserted_normal($a, $b) {
assert(var_dump(func_get_args()));
}
function
asserted_string($a, $b) {
assert('var_dump(func_get_args())');
}
?>

<?php asserted_normal(1,2) ?> prints
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}

but <?php asserted_string(3,4) ?> prints
array(1) {
[0]=>
string(25) "var_dump(func_get_args())"
}

This is because of that the string passed to assert() is being evaled inside assert, and not your function. Also, note that this works correctly, because of the eval scope:

<?php
function asserted_evaled_string($a, $b) {
assert(eval('var_dump(func_get_args())'));
}
asserted_evaled_string(5,6);
?>
array(2) {
[0]=>
int(5)
[1]=>
int(6)
}

(oh, and for simplicity's sake the evaled code doesn't return true, so don't worry that it fails assertion...)
up
1
Julien MOREAU aka PixEye
2 years ago
In order to change zend.assertions or assert.exception values, try with the ini_set() function but be aware that it may fail.

Example:
<?php
$ret
= @ini_set('zend.assertions', '1');
if (
$ret === false) echo 'ini_set() failed before line ', __LINE__, PHP_EOL;
up
-1
jason at jaypha dot com
6 years ago
You can take advantage of how assert is handled to use it for crude conditional compilation.

For example

<?php
assert
(print("Some debug message\n"));
assert(($val = "dev") || true);
?>

Since print() always returns 1, the topmost assertion will pass. For others, you may need to add a || true. Always enclose the expression in ().

In a development environment where zend.assertions=1, the above code will execute. In production environments where zend.assertions=-1, it wont even compile, thus not burdening performance.

Another, more real world, example.

<?php
$cssSrc
= 'https://code.jquery.com/jquery-3.2.1.min.js';
assert(($cssSrc = 'http://dev.local/jquery-3.2.1.js') || true);
echo
"<link rel='stylesheet' type='text/css' href='$cssSrc'/>\n";
?>

In a production environment, The website will use the minified version from the CDN. In a development environment, a development version, sourced locally, will be used instead.

Note: This will not work for everything. Only code that can be embedded in an expression will work.
up
-5
uramihsayibok, gmail, com
13 years ago
There's a nice advantage to giving assert() some code to execute, as a string, rather than a simple true/false value: commenting.

<?php

assert
('is_int($int) /* $int parameter must be an int, not just numeric */');

// and my personal favorite
assert('false /* not yet implemented */');

?>

The comment will show up in the output (or in your assertion handler) and doesn't require someone debugging to go through your code trying to figure out why the assertion happened. That's no excuse to not comment your code, of course.

You need to use a block comment (/*...*/) because a line comment (//...) creates an "unexpected $end" parse error in the evaluated code. Bug? Could be.
(You can get around it with "false // not yet implemented\n" but that screws up the message)
up
-8
office dot stojmenovic at gmail dot com
10 years ago
Example from Ikac Framework how they use assert()

<?php

/**
* Set Assertion Debug
*
* This method will check the given assertion and take appropriate -
* action if its result is FALSE.
*
* This file is part of Ikac Framework.
*
* @package Ikac Framework
* @author Ivan Stojmenovic Ikac <contact.@stojmenovic.info>
*
* @param mixed $assertion The assertion.
* @param mixed $callback Callback to call on failed assertions
* @param array $options Set the various control options or just query their current settings.
* @param string $description An optional description that will be included in the failure message if the assertion fails.
*/
public function setAssertionDebug($assertion, $callback, array $options, $description = null)
{
if (
is_array($options)) {
foreach (
$options AS $option => $value) {
assert_options($option, $value);
}
}
if (
$callback) {
assert_options(ASSERT_CALLBACK, $callback);
}

return
assert($assertion, $description);
}
?>

How to use:

<?php
use Ikac\Component\SystemBehaviour\OptionsInfo;

$system = new OptionsInfo();

$option = array(ASSERT_ACTIVE => 1,ASSERT_WARNING => 0,ASSERT_QUIET_EVAL => 1);

$system->setAssertionDebug('2<1', function(){
echo
"Assertion failed";
},
$option);

?>
up
-4
Ben
7 years ago
if there was no 'warning' message when assertion failed (FALSE), try reset the error handler:
<?php
set_error_handler
( null );
To Top