Po co return true, return false?

1

Kolejne pytanie z serii trywialnych

https://pl.wikibooks.org/wiki/PHP/Klasy_i_obiekty

po jaką cholerę są tu return true i false w funkcji - klasy i to w dodatku warunku if? Co mają za zadanie? Sprawdziłem i praktycznie nie widzę żadnej różnicy pomiędzy tym, czy one są czy też ich nie ma.

2

Służą one do podstawowego raportowania błędów. Użytkownik klasy poprzez sprawdzenie wartości zwracanej dostaje informację, czy operacja wykonywana przez metodę się powiodła (true), czy wystąpił błąd (false).

2

Przy czym zaproponowane tam rozwiązanie to jakaś patologia imho, bo upośledza normalnie funkcjonowanie setterów (mam na myśli ify) - zwracanie false również jest dziwne, ponieważ z reguły oczekuje się, że setter zwróci modyfikowany obiekt (umożliwiając tzw. method chaining). Wygląda to na poradnik pisany przez jakiegoś newbie.

1

Ja bym się trzymał z daleka od poradników z wikipedii. Zobacz to: https://4programmers.net/Forum/1378611

0

@Desu: powiedz mi po co uzywac true lub false jak sam if wystarcza

If(bagietka == 5){
Cos wykonaj
}
Czy
If(bagietka == 5){
Cos wykonaj
Return true;
}else{
Return false;
}

2

Ja bym zrobił jeszcze inaczej:

if($bagietka !== 5) {
    return; // lub return false, lub throw new InvalidArgumentException, zależy co chcemy zakomunikować wywołującemu metodę
}

// zrób coś z bagietką

To się nazywa early return, dzięki któremu unikamy niepotrzebnego zagnieżdżenia.

Jeżeli chodzi o settery, to częstszą praktyką jest coś, co się nazywa fluent interface, czyli:

class Foo {
    private $a;
    
    private $b;

    public function setA($a)
    {
        $this->a = $a;

        return $this;
    }

    public function setB($b)
    {
        $this->b = $b;

        return $this;
    }
}

$foo = new Foo();
$foo->setA(1)->setB(2);

Zazwyczaj się to spotyka, jak masz do czynienia z jakimś obiektem typu builder, czyli coś składasz, np. zapytanie:

$builder = $this->createQueryBuilder()->select('*')->from('tabela')->join('...')

Więc jak widać nie ma tu miejsca na return true/false. Osobiście chyba się nie spotkałem z tym, żeby setter zwracał true/false. Ja bym zrobił coś takiego:

public function setEmail($email)
{
    if (strpos($email, '@') === false) {
        throw new \InvalidArgumentException("Błędny email");
    }
    
    $this->email = $email;
} 

Wtedy mam pewność, że ktoś musi coś z tym zrobić. Jeżeli zwrócisz false, to utrudnisz debuggowanie, bo błąd przemknie się niepostrzeżenie, bo ktoś może zapomnieć o sprawdzeniu i zamiast tak:

if(!$obj->setEmail($email)) {
  // oops cos sie nie udało, ktoś chyba podał zły email
}

zrobi tak:

$obj->setEmail($email);

// jedziemy dalej z logiką
// 15000 linii kodu dalej próbujemy wysłać email, ooops email jest pusty oO przecież był set.. tylko się nie udał bo zwrócił false oO

I coś się zesra, ale dopiero w miejscu, gdzie ten Twój email faktycznie musi być emailem, bo przeprowadzasz na nim jakies operacje. I wtedy zaczyna się szukanie.. czemu email jest pusty. Jak walniesz exception, to się ktoś od razu zorientuje ;)

2

Co to ma być?

Desu napisał(a):
public function setEmail($email)
{
    if (strpos($email, '@') === false) {
        throw new \InvalidArgumentException("Błędny email");
    }
    
    $this->email = $email;
} 

Tutaj walidacja email regexp-em:

public function validEmail($email)
{
    $regex = '/^[-_a-z0-9\'+*$^&%=~!?{}]++(?:\.[-_a-z0-9\'+*$^&%=~!?{}]+)*+@(?:(?![-.])[-a-z0-9.]+(?<![-.])\.[a-z]{2,6}|\d{1,3}(?:\.\d{1,3}){3})$/iD';
    $result = (bool) preg_match($regex, (string) $email);
    return $result;
}
0

@drorat1: nie chodził o to, jak walidować email, ale jak już przy tym jesteśmy, to nie ma sensu pisać regex samemu, bo jest filter_var (tylko nie pamiętałem składni, a nie chciało mi sie googlować).

Regex używany przez php: https://github.com/php/php-src/blob/40ecad34022b6e687cc654d47c88f8cef5d418fd/ext/filter/logical_filters.c#L607

2

@Desu: imho walidacja danych w setterach to mocny downer, i powinna być ona wydzielona do osobnej funkcji (lub w ogóle klasy) - z dwóch/trzech powodów:

1.Jeśli setter będzie wywoływany po drodze wiele razy, walidacja będzie również wykonywana kilkukrotnie (co ma znaczenie, jeśli np. walidujemy istnienie rekordu).

2.Może zaistnieć sytuacja, w której będzie potrzebna walidacja oparta na wartości na przykład dwóch pól, co również komplikuje sprawę w przypadku walidacji w setterach.

3.SRP.

0

@Patryk27: czyli w zasadzie w settarach nie powinno być walidacji? W sumie to ma sens. Można krytyczne dla działania aplikacji skalary wydzielać do value objects i wymuszać ich prawidłowość przez type hit.

0

Biorąc pod uwagę to że taka klasa Person, reprezentująca kogoś, gdzie nadaje się imię i nazwisko, wiek i inne rzeczy np. numer telefonu, email mogła by być równie dobrze i typu stdClass to ta walidacja w praktyce może być coś na kształt tego:


//  dla przykładu to zawiera $_POST przy wysłaniu czegoś z formularza
$post = array(
    'csrf' => 'df64328ccd3c86c4c833d9406a93e12de472bbe31987cd8e4323a3806609bc6e',
    'name' => 'John',
    'surname' => 'Doe',
    'email' => '[email protected]',
    'phone' => '666 777 888',
);

$validation = Validation::factory($post)
    ->rule('csrf', 'not_empty')
    ->rule('csrf', 'Security::check')
    ->rule('name', 'not_empty')
    ->rule('surname', 'not_empty')
    ->rule('email', 'not_empty')
    ->rule('email', 'email')
    ->rule('phone', 'not_empty')
    ->rule('phone', 'phone');

if ($validation->check())
{
    $person = new stdClass;
    $person->name = $post['name'];
    $person->surname = $post['surname'];
    $person->email = $post['email'];
    $person->phone = $post['phone'];    

    // i dowolne operacje np. wstawianie do bazy przy użyciu PDO czy cokolwiek innego
}
else
{
   // a te błędy walidacji się mogą np. wyświetlać w formularzu
    $errors = $validation->errors();
}

A tu kody żeby nie było skąd to wszystko:

https://docs.koseven.ga/guide-api/Valid
https://docs.koseven.ga/guide-api/Validation
https://docs.koseven.ga/guide-api/Security

1 użytkowników online, w tym zalogowanych: 0, gości: 1