web-dev-qa-db-de.com

Richtige Handhabung PHP 7 Rückgabetypen

Ich bin damit beschäftigt, eine Anwendung zu erstellen, und ich möchte die PHP 7-Rückgabetypen verwenden. Nun habe ich auf php.net gelesen, dass es eine Entwurfsentscheidung war, dass es nicht erlaubt ist, null zurückzugeben, wenn ein Rückgabetyp definiert wird.

Was ist der richtige Weg, um damit umzugehen?

Eine Option ist ein try ... catch Block:

public function getMyObject() : MyObject
{ 
     return null;
}

try
{
    getMyObject();
}
catch(Exception $e)
{
    //Catch the exception
}

Ich habe kein gutes Gefühl, weil mein Code ein großer Versuch sein wird ... catch-Block, da ich einen try ... catch-Block für jede Methode schreiben muss, die ein Objekt zurückgibt.

Das Null Object Pattern ist eine gute Lösung dafür, aber ich mag die Idee nicht, eine NullObject für jedes Objekt in meiner Anwendung zu erstellen. Gibt es einen richtigen Weg, dies zu tun? 

27
S.Pols

Ich habe kein gutes Gefühl, da mein Code ein riesiger try/catch-Block sein wird, da ich für jede Methode, die ein Objekt zurückgibt, einen try/catch-Block schreiben muss.

Die Alternative (mit Ihrem Code) wäre, den zurückgegebenen Wert für null immer zu überprüfen, um keine Fehler durch die Verwendung von null als Objekt zu erhalten.

Die Verwendung von Ausnahmen ist ausdrucksvoller und macht Fehler früh sichtbar, was eine gute Sache ist. Stellen Sie also sicher, dass Ihre Methode immer ein Objekt zurückgibt, oder lösen Sie eine Ausnahme aus, wenn sie ihren Vertrag nicht erfüllen kann. Ansonsten hat der Rückgabetyp keinen reellen Wert.

6

Wenn Ihr Code erwartet, eine Instanz einer Klasse zurückzugeben, in diesem Fall MyObject, dies jedoch nicht, ist dies tatsächlich eine Ausnahme und sollte als solche behandelt werden.

Sie sollten diese Ausnahme jedoch selbst auslösen.

public function getMyObject() : MyObject
{
    throw new MyCustomException("Cannot get my object");
}

Dann können Sie diese bestimmte Ausnahme abfangen und entsprechend fortfahren.

27

Sie können den Datentyp Option verwenden.

Dies ist ein Typ, der Something oder Nothing als umschlossenen Wert hat.

Eine ausführlichere Beschreibung hier und eine der offenen Implementierungen in PHP finden Sie hier

PS: Bitte verwenden Sie keine Ausnahmen, Out-Parameter oder zusätzliche Methoden für diese Art von Logik. Dies ist ein falsches Werkzeug für den Job.

6
nikita2206

Dies ist derzeit nicht möglich, obwohl es, wie erwähnt, RFCs gibt, die das Problem für zukünftige Versionen beheben könnten.

Ab jetzt sind Ihre Optionen:

1.Legen Sie den Rückgabetyp von Ihrer Methodensignatur ab:

public function getMyObject()
{ 
     return null;
}

2. Throw und fange eine Ausnahme (wie in der Antwort von @ NiettheDarkAbsol):

public function getMyObject() : MyObject
{
    throw new MyCustomException("Cannot get my object");
}

3.Refaktor für zwei Methoden:

private $myObject;
//TODO think of a better method name
public function canGetMyObject() : bool
{
    $this->myObject = new myObject();
    return true;
}

public function getMyObject() : MyObject
{
    if(!$this->myObject){
        throw new MyCustomException("Cannot get my object");
    }
    return $this->myObject;
}

Aufrufcode:

if($cls->canGetMyObject()){
    $myObject  = $cls->getMyObject();
}

4.Verwenden Sie einen Bool-Rückgabetyp und einen Out-Parameter:

public function tryGetMyObject(&$out) : bool
{
    $out = new myObject();
    return true;
}

Aufrufcode:

$myObject = null;

if($cls->tryGetMyObject($myObject)){      
    $myObject->someMethod(); //$myObject is an instance of MyObject class
}

Die 3. und 4. Option sind nur dann wirklich in Betracht zu ziehen, wenn eine Null-Rückkehr erwartet wird und häufig auftritt, so dass der Overhead von Ausnahmen ein Faktor ist nach vorne

3
Steve

Ab PHP7.1 können Sie nullfähige Rückgabetypen verwenden:

public function getMyObject(): ?MyObject {
  return null;
}

http://php.net/manual/de/migration71.new-features.php

1
Jared

Ich wollte dasselbe verlangen. Ich sehe nicht viel Sinn dafür.

Wenn ich den folgenden Beispielcode habe, um User nach Namen zu finden:

<?php

class User
{
    protected $name;

    /**
     * User constructor.
     *
     * @param $name
     */
    public function __construct(string $name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getName() : string
    {
        return $this->name;
    }
}


function findUserByName(string $name, array $users) : User {
    foreach ($users as $user) {
        if ($user->getName() == $name) {
            return $user;
        }
    }

    return null;
}


$users = [
    new User('John'), new User('Daniel')
];

$user = findUserByName('John', $users);

echo $user->getName()."\n";

$user2 = findUserByName('Micheal', $users);

Ich möchte Php sagen, dass ich entweder User oder Null erhalten kann. Jetzt muss ich es immer in try catch block einwickeln und ich sehe in diesem Fall keinen Sinn darin, den Rückgabetyp zu deklarieren. Auf der anderen Seite Wenn meine findUserByName-Funktion komplex wäre, könnte ich versehentlich beispielsweise den Benutzernamen anstelle des vollständigen Benutzerobjekts zurückgeben, so dass ich den Rückgabetyp definieren möchte.

Sinnvoller wäre es, mehrere Rückgabetypen für Funktionen zu definieren. Manchmal erstellen Sie eine Funktion, die ein Objekt oder ein Array von Objekten zurückgibt, und es wäre schön, diese Funktion zu definieren. Diese Funktion sollte beispielsweise User oder ein Array von Benutzern zurückgeben: User[]

Im OP-Fall (und auch bei mir) könnten wir dann den Rückgabetyp als User, null deklarieren und das Problem dadurch lösen.

0