PHP-Typ-Hinweis auf primitive Werte?

73

Ich würde gerne wissen, ob man eine Methode tippen kann, um primitive Typen zu erwarten?

Etwas wie das:

public function someMethod(string $str)
                         //^^^^^^

Oder:

private function anotherMethod(int $num)
                             //^^^

genauso wie du:

private function otherMethod(Person $rambo)
                           //^^^^^^

Ist das in PHP möglich?

Felipe
quelle
2
hier Typ Hinweis, php.net/manual/en/language.oop5.typehinting.php
Pramendra Gupta
10
nur mit PHP 7
zloctb
Oder Sie können args Modul von NSPL verwenden, wenn Sie nicht PHP 7.x verwenden
Ihor Burlachenko

Antworten:

86

In PHP 7 haben sie Folgendes hinzugefügt:

Mit Typdeklarationen können Funktionen erfordern, dass Parameter zum Zeitpunkt des Aufrufs von einem bestimmten Typ sind. Wenn der angegebene Wert vom falschen Typ ist, wird ein Fehler generiert: In PHP 5 ist dies ein behebbarer schwerwiegender Fehler, während PHP 7 eine TypeError-Ausnahme auslöst.

Referenz: http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration


Als diese Antwort gefragt wurde, war PHP 5 die neueste und sagte Folgendes:

PHP 5 führt Typhinweise ein. Funktionen können nun erzwingen, dass Parameter Objekte (durch Angabe des Namens der Klasse im Funktionsprototyp), Schnittstellen, Arrays (seit PHP 5.1) oder aufrufbar (seit PHP 5.4) sind . Wenn jedoch NULL als Standardparameterwert verwendet wird, ist dies als Argument für einen späteren Aufruf zulässig.

Wenn eine Klasse oder Schnittstelle als Typhinweis angegeben ist, sind auch alle untergeordneten Elemente oder Implementierungen zulässig.

Typhinweise können nicht mit skalaren Typen wie int oder string verwendet werden. Ressourcen und Eigenschaften sind ebenfalls nicht erlaubt.

Referenz: http://php.net/manual/en/language.oop5.typehinting.php

afuzzyllama
quelle
1
OK. Vielen Dank. Sie rechnen damit, dass sie es in Zukunft jederzeit zur Verfügung stellen werden? Oder ist es nicht "kompatibel mit der PHP-Philosophie", wie sie sagen?
Felipe
1
@Felipe ist eine dieser Situationen, in denen es dem PHP-Team egal ist / sich überhaupt nicht ändern möchte, selbst wenn das vorhandene Verhalten fehlerhaft oder unerwünscht ist. Ihr Issue-Tracker ist voll von diesem Zeug; Siehe meine Antwort für das spezifische Problem im Zusammenhang mit Typhinweisen.
Rafe Kettler
Ich glaube nicht, dass PHP den Wunsch hat, bald Typen zu verwenden. Warum machst du dir Sorgen um Typen?
Afuzzyllama
@Rafe Kettler wie so? Laut w3c ist es nicht. Mir ist sowieso nicht bekannt, eine Variable an einen bestimmten Typ zu binden.
Afuzzyllama
21
@afuzzyllama w3schools ist nicht w3c. w3c stört sie die ganze Zeit, um die Leute nicht mehr irrezuführen und zu glauben, dass sie sie sind. Die PHP-Entwickler behaupten, dass es stark typisiert ist (was wirklich die einzige Voraussetzung für eine starke Typisierung ist), aber das ist es wirklich nicht. Ich weiß nicht, was ich dachte, als ich kommentierte, dass es stark getippt war.
Rafe Kettler
29

Nee. Sie können keinen Hinweis für Grundelemente eingeben, da PHP automatische Konvertierungen für Grundelemente bietet. Siehe http://bugs.php.net/bug.php?id=29508 . Dies wird sich nie ändern, es sei denn, das PHP-Team hat eine plötzliche Herzensveränderung (was zweifelhaft ist, sie sind ziemlich stur).

Rafe Kettler
quelle
9
Update für 2015 und kommende PHP7: phpclasses.org/blog/post/…
timhc22
16

Ja, jetzt ist es möglich. Nach einer langen Diskussion wurde gerade ein Vorschlag zur Implementierung von Typhinweisen für Skalarfunktionsparameter und Rückgabewerte mit der höchsten Stimmenzahl genehmigt. Überprüfen Sie auf Details:

Skalare Typhinweise bestehen aus der Deklaration der Typen von Funktionsparametern und Rückgabewerten, die vom Typ int, float, string und bool sein können. Auf diese Weise kann die PHP-Laufzeit-Engine überprüfen, ob die an Parameterfunktionen und Rückgabewerte übergebenen Wertetypen von sind die erwarteten Typen, um eventuelle Programmierfehler zu erkennen. Tipphinweise für Objekte, Arrays und Callables waren bereits in früheren PHP-Versionen zulässig. Die aktuelle Implementierung führt fünf neue reservierte Wörter ein: int, float, bool, string und numeric. Diese waren bisher nicht reserviert, da das Gießen im Lexer ein Sonderfall ist.

Example :
function test(float $a) {
    var_dump($a); 
}

test(1); // float(1)
test("1"); // float(1)
test(1.0); // float(1)
test("1a"); // E_RECOVERABLE_ERROR
test("a"); // E_RECOVERABLE_ERROR
test(""); // E_RECOVERABLE_ERROR
test(1.5); // float(1.5)
test(array()); // E_RECOVERABLE_ERROR
test(new StdClass); // E_RECOVERABLE_ERROR

Sie haben auch die Möglichkeit, in eine Quelldatei zu deklarieren, in der Sie Hinweise auf Scaler-Typen zulassen können. Dies muss die erste Zeile Ihres Konfigurationsskripts sein und kann nicht an anderer Stelle in derselben Datei deklariert werden.

Like : declare(strict_types=1);

Wenn die PHP-Engine zur Laufzeit versucht, einen Wert zurückzugeben, prüft sie, ob sie nicht mit der angegebenen übereinstimmt. Sie gibt einen schwerwiegenden Fehler aus, wie z. B. Schwerwiegender Fehler: Argument 1, das an increment () übergeben wird, muss vom Typ Integer sein, Zeichenfolge angegeben

Mit diesen neuen Deklarationsfunktionen können Sie robustere Anwendungen schreiben, indem Sie frühzeitige Programmierfehler erkennen, die durch die Übergabe von Werten des falschen Typs an Funktionen verursacht werden.

Es kann auch zu automatischen Typänderungen kommen. Beispielsweise können int-Typen automatisch in Float-Typparameter geändert werden.

function test(float $x){
    var_dump($x);
}
test(10); // works fine

Rückgabe des Rückgabetyps

Wir können die Rückgabetypen deklarieren, indem wir einen Doppelpunkt gefolgt vom erwarteten Typ zwischen der letzten Klammer und der ersten Klammer in der Funktionsdeklaration hinzufügen.

Für Funktionen, die keinen Wert zurückgeben, sollte im Abschnitt zur Deklaration des Rückgabetyps nichts hinzugefügt werden.

function mustReturnInt(): int { ... }
function mustReturnString(): string { ... }
function mustReturnBool(): bool { ... }
function mustReturnFloat(): float { ... }
function doesNotReturnAnything() { ... }

Ein etwas komplexeres Beispiel

declare(strict_types=1);  
class StrictTypesTestingClass {  
public function returnSameInt(int $value): int {   return $value;  }   
public function returnSameFloat(float $value): float {   return $value;  }  
public function returnSameString(string $value): string {   return $value;  }   
public function returnSameBool(bool $value): bool {   return $value;  } }  
$check = new StrictTypesTestingClass();  // calls that work  print $check->returnSameInt(10); 
print $check->returnSameFloat(10.0); 
print $check->returnSameString("test"); 
print $check->returnSameBool(true) ? 'true' : 'false';  // calls that throw exceptions 
print $check->returnSameInt("10"); 
print $check->returnSameFloat("10.0"); 
print $check->returnSameString(10);
print $check->returnSameBool("true");

Verhalten der schwachen Typprüfung und Typkonvertierung: Der schwache Typprüfungsmodus kann mit der Anweisung declare (strict_types = 0) verwendet werden. oder das Fehlen der strengen Typendeklaration. Es gibt einige Punkte, die berücksichtigt werden müssen: Aufrufe einer Erweiterung oder integrierten PHP-Funktion mit schwachen Typprüfungen haben dasselbe Verhalten wie in früheren PHP-Versionen. Die Regeln für die schwache Typprüfung für neue skalare Typdeklarationen sind größtenteils dieselben wie die von Erweiterung oder integrierte PHP-Funktionen. NULL ist ein Sonderfall, um mit den aktuellen Typdeklarationen für Klassen, aufrufbare Dateien und Arrays übereinzustimmen. NULL wird standardmäßig nicht akzeptiert, es sei denn, es ist ein Parameter und erhält explizit den Standardwert NULL, zum Beispiel: Funktionsbeispiel (int $ a = NULL);

Dieser Ansatz bietet viele Vorteile. Sie erhalten Typensicherheit. Das heißt, Sie können den Code endlich statisch analysieren! Sie können Fehler erkennen, bei denen Sie versehentlich eine Zeichenfolge von einer Funktion übernehmen und als Ganzzahl an eine andere übergeben. Für mich, einen Entwickler, der täglich PHP verwendet und Java als Referenz für OOP-Sprachen betrachtet, ist dies ein großer Fortschritt für PHP .

Purushottam
quelle
Ist das nicht eher Hack als PHP?
Felipe
Ist das echt? In welcher Version können wir erwarten, dass diese Funktionen Premiere haben?
Robbmj
FYI ... Typ numerisch existiert nur, wenn es eine Klasse oder Schnittstelle mit diesem Namen gibt.
DigiLive
6

Alle haben es bereits gesagt, Sie können keinen Tipp für Primitive eingeben, da PHP dies nicht unterstützt. Der Grund dafür liegt nicht nur in der automatischen Konvertierung, sondern auch in der Reaktion der Community.

Bisher kann ich mich daran erinnern, dass im Mai 2010 die Unterstützung für skalare Typ-Hinweise zum PHP-Trunk hinzugefügt wurde. Aufgrund der Reaktion der Community schaffte es diese Funktion jedoch nicht in die Version 5.4.

Es gab einige Kontroversen darüber. Diejenigen, die sich der Änderung widersetzten, argumentierten, dass diese Unterstützung gegen die grundlegenden Designs von PHP verstoßen würde. PHP wird als schwach typisierte Sprache angesehen. Im Wesentlichen bedeutet dies, dass Sie für PHP keine Datentypen deklarieren müssen. Mit Variablen sind noch Datentypen verknüpft, aber Sie können radikale Dinge wie das Hinzufügen einer Zeichenfolge zu einer Ganzzahl ausführen, ohne dass dies zu einem Fehler führt.

IMHO: Skalar-Typ-Hinweise sollten so schnell wie möglich in PHP hinzugefügt werden. Dies ist eine Funktion, die wir alle benötigen. Ich respektiere wirklich, dass PHP eine schwach typisierte Sprache ist, aber für die High-End-Entwicklung und -Produktion, insbesondere in OO-Kontexten, sind Skalar-Typ-Hinweise ein Muss. Wir können beide Alternativen in PHP haben, genau wie prozedurale und OO.

TCB13
quelle
3

Ja, es ist möglich.

http://ru2.php.net/manual/ru/language.oop5.typehinting.php#83442

Achtung: es ein Tippfehler in Original - Handbuch ist: res ro uce statt res ou rce

Die Leute fragen oft nach skalaren / grundlegenden Schreibweisen. Hier ist ein Drop-in-Class, den ich in meinem MVC-Framework verwende und der Typeinträge mithilfe eines benutzerdefinierten Fehlerbehandlers ermöglicht.

Hinweis: Sie sollten diesen Code vor allen anderen Codes in Ihre Include-Header aufnehmen. Wenn Sie die Funktion set_error_handler () verwenden, sollten Sie sich darüber im Klaren sein, dass dieser ebenfalls verwendet wird. Möglicherweise müssen Sie Ihre set_error_handlers () verketten

Warum?

  1. Weil die Leute es satt haben, die is_ * -Funktionen zum Validieren von Parametern zu verwenden.
  2. Reduzierung der redundanten Codierung für defensive Codierer.
  3. Funktionen / Methoden definieren sich selbst / dokumentieren die erforderlichen Eingaben.

Folgen Sie auch der Diskussion für Schreibweisen in PHP 6.0 auf den PHP Internals-Boards.

<?php

define('TYPEHINT_PCRE', '/^Argument (\d)+ passed to (?:(\w+)::)?(\w+)\(\) must be an instance of (\w+), (\w+) given/');

class Typehint
{

    private static $Typehints = array(
        'boolean'   => 'is_bool',
        'integer'   => 'is_int',
        'float'     => 'is_float',
        'string'    => 'is_string',
        'resource'  => 'is_resource'
    );

    private function __Constrct() {}

    public static function initializeHandler()
    {

        set_error_handler('Typehint::handleTypehint');

        return TRUE;
    }

    private static function getTypehintedArgument($ThBackTrace, $ThFunction, $ThArgIndex, &$ThArgValue)
    {

        foreach ($ThBackTrace as $ThTrace)
        {

            // Match the function; Note we could do more defensive error checking.
            if (isset($ThTrace['function']) && $ThTrace['function'] == $ThFunction)
            {

                $ThArgValue = $ThTrace['args'][$ThArgIndex - 1];

                return TRUE;
            }
        }

        return FALSE;
    }

    public static function handleTypehint($ErrLevel, $ErrMessage)
    {

        if ($ErrLevel == E_RECOVERABLE_ERROR)
        {

            if (preg_match(TYPEHINT_PCRE, $ErrMessage, $ErrMatches))
            {

                list($ErrMatch, $ThArgIndex, $ThClass, $ThFunction, $ThHint, $ThType) = $ErrMatches;

                if (isset(self::$Typehints[$ThHint]))
                {

                    $ThBacktrace = debug_backtrace();
                    $ThArgValue  = NULL;

                    if (self::getTypehintedArgument($ThBacktrace, $ThFunction, $ThArgIndex, $ThArgValue))
                    {

                        if (call_user_func(self::$Typehints[$ThHint], $ThArgValue))
                        {

                            return TRUE;
                        }
                    }
                }
            }
        }

        return FALSE;
    }
}

Typehint::initializeHandler();

?>

An are some examples of the class in use:

<?php

function teststring(string $string) { echo $string; }
function testinteger(integer $integer) { echo $integer; }
function testfloat(float $float) { echo $float; }

// This will work for class methods as well.

?>

Du bekommst das Bild..

Sergii Smirnov
quelle
1

Gemäß primären PHP-Dokumentationstyphinweisen wird dies für primitive Typen nicht unterstützt.

Es wird jedoch für Klassen und Schnittstellen unterstützt.

Bearbeiten: Ich habe vergessen zu erwähnen, dass dies auch für Arrays unterstützt wird.

Luc M.
quelle
Hmmm .. Ich glaube nicht, dass es für Schnittstellen unterstützt wird ... Oder irre ich mich?
Felipe
1
Ich mache das für die Schnittstelle. Dann bin ich mir ziemlich sicher, dass du falsch liegst :-)
Luc M
Hmm ... Ich habe genau diese Frage vor einiger Zeit gestellt. Und ich hatte den allgemeinen Eindruck, dass es nicht funktioniert. Schauen Sie hier stackoverflow.com/questions/5346393/…
Felipe
Ich muss einige Tests mit meinem Code durchführen ... Ich habe Methoden wie MyMethod (iMyInterface $ some_interface) ... Und wenn ich etwas übergebe, das die Schnittstelle iMyInterface nicht implementiert, wird es nicht "kompiliert". Ich habe jedoch nicht versucht, eine Klasse mit dem Namen der zu implementierenden Methoden zu übergeben, ohne die Schnittstelle zu implementieren.
Luc M
0

Hier ist eine kurze Syntax zum Erzwingen eines booleschen Werts aus einem übergebenen Parameter. Wenn $statewahr ist, $this->is_activewird auf wahr gesetzt. Für alle anderen Wertetypen wird der Wert auf false gesetzt.

function set_active ( $state ) {
    $this->is_active = true === $state;
}
Lee Blue
quelle
-3

Ich denke, Sie brauchen keine Typhinweise für PHP, da Sie Typprüfungsfunktionen wie is_bool (), is_string () usw. usw. erhalten, sodass Sie überprüfen können, was auch immer Sie versuchen, gegen diese Funktionen zu argumentieren, bevor Sie es tatsächlich machen ein Argument, obwohl die Methode, mit der sie Array- und Objekttypen überprüfen, viel sauberer wäre.

Carwyn Stephen
quelle
5
Tipphinweise würden verhindern, dass if(!is_bool($bool)) throw new InvalidTypeException('Arg $bool must be a boolean');für jedes Argument in jeder Funktion unnötig wird. Wenn ich solide APIs entwerfe, gebe ich immer check my args ein. Und Tipphinweise würden viele if-Anweisungen cleaner
SPAREN