Hodnota 0 se tváří jako null

ForestCZE
Člen | 209
+
0
-

Ahoj, mám metodu v modelu:

public function getEmployees(?int $jobGrade, ?string $search)
    {
        if(!$jobGrade && !$search)
            return $this->database->getCharacters()->where('job = ? OR job1 = ? OR job2 = ?', self::JOB, self::JOB, self::JOB);

        if($jobGrade)
            return $this->database->getCharacters()->where('(job = ? AND job_grade = ?) OR (job1 = ? AND job_grade1 = ?) OR (job2 = ? AND job_grade2 = ?)', self::JOB, $jobGrade, self::JOB, $jobGrade, self::JOB, $jobGrade)->fetchAll();

        if($search)
        {
            $s = explode(" ", $search);
            if(count($s) == 1)
                return $this->database->getCharacters()->where('(job = ? OR job1 = ? OR job2 = ?) AND (LOWER(lastname) LIKE ? OR LOWER(firstname) LIKE ?)', self::JOB, self::JOB, self::JOB, '%' . strtolower($s[0]) . '%', '%' . strtolower($s[0]) . '%')->fetchAll();
            else
                return $this->database->getCharacters()->where('(job = ? OR job1 = ? OR job2 = ?) AND (LOWER(lastname) LIKE ? AND LOWER(firstname) LIKE ?) OR (LOWER(lastname) LIKE ? AND LOWER(firstname) LIKE ?)', self::JOB, self::JOB, self::JOB, '%' . strtolower($s[0]) . '%', '%' . strtolower($s[1]) . '%', '%' . strtolower($s[1]) . '%', '%' . strtolower($s[0]) . '%')->fetchAll();
        }
    }

Poté podmínku a zavolání v presentru:

public function actionEmployees($jg, $search, $page = 1): void
    {
        if(!$jg && !$search)
            $this->employees = $this->character->getEmployees(intval($jg), $search)->page($page, 20, $this->employeesLastPage);
        else
            $this->employees = $this->character->getEmployees(intval($jg), $search);
    }

Když mám v url jg=0, tak to bere jako že se podmínka splnila a neskočí to do else. Jenže !$jg přeci není to samé jako jg=0.

Co dělám špatně?

Editoval ForestCZE (15. 6. 2021 22:31)

Marek Bartoš
Nette Blogger | 1146
+
+5
-

Doporučuju prostudovat tyto zdroje: https://www.php.net/…parisons.php a https://www.php.net/….boolean.php#…

Vykřičník funguje tak, že hodnotu zkonvertuje na bool a zneguje. V podstatě tedy (bool) $jg === false. PHP při konverzi hodnot používá loose comparisons, což v praxi znamená, že při konverzi na bool se z jakékoli „prázdné“ hodnoty stane false – false, null, prázdný string, prázdné pole, nula a překvapivě i prázdný SimpleXML element.

Abys na to, kde zrovna konverze je bezpečná nebo není nemusel myslet, je lepší se jí vyhnout úplně. Vykřičník by se měl používat pouze na bool (s přivřenýma očima bool|null) a místo dvojitého provnávání (==, !=, <=, atd) použít trojité (===, !==, <==)

V tvém případě bys tedy napsal $jg !== null.

Takovéhle problémy ti umí podchytit phpstan, tenhle konkrétní problém myslím řeší balíček phpstan-strict-rules. Doporučuju si na to udělat čas, phpstan používat a doplnit si všude datové typy. Umí to ušetřit hodně starostí.

ali
Člen | 342
+
0
-

Ja bych rekl, ze se to chova podle ocekavani

https://3v4l.org/7i7i9

ForestCZE
Člen | 209
+
0
-

Marek Bartoš napsal(a):

Doporučuju prostudovat tyto zdroje: https://www.php.net/…parisons.php a https://www.php.net/….boolean.php#…

Vykřičník funguje tak, že hodnotu zkonvertuje na bool a zneguje. V podstatě tedy (bool) $jg === false. PHP při konverzi hodnot používá loose comparisons, což v praxi znamená, že při konverzi na bool se z jakékoli „prázdné“ hodnoty stane false – false, null, prázdný string, prázdné pole, nula a překvapivě i prázdný SimpleXML element.

Abys na to, kde zrovna konverze je bezpečná nebo není nemusel myslet, je lepší se jí vyhnout úplně. Vykřičník by se měl používat pouze na bool (s přivřenýma očima bool|null) a místo dvojitého provnávání (==, !=, <=, atd) použít trojité (===, !==, <==)

V tvém případě bys tedy napsal $jg !== null.

Takovéhle problémy ti umí podchytit phpstan, tenhle konkrétní problém myslím řeší balíček phpstan-strict-rules. Doporučuju si na to udělat čas, phpstan používat a doplnit si všude datové typy. Umí to ušetřit hodně starostí.

Jestli jsem to pochopil správně, tak by mělo pomoct upravit podmínku

if(!$jobGrade && !$search) na if($jg === null && !$search)

pak to do else skočí, ale databáze zavolá:

SELECT * FROM `users` WHERE (`job` = 'ambulance' OR `job1` = 'ambulance' OR `job2` = 'ambulance')

místo:

SELECT * FROM `users` WHERE ((`job` = 'ambulance' AND `job_grade` = 0) OR (`job1` = 'ambulance' AND `job_grade1` = 0) OR (`job2` = 'ambulance' AND `job_grade2` = 0))

takže metoda vrátí první return, nikoliv druhý. I v té metodě ve třídě musím nějak upravit ty podmínky?

Editoval ForestCZE (15. 6. 2021 23:22)

Marek Bartoš
Nette Blogger | 1146
+
+3
-

Uprav si to všude, kde chceš rozlišovat mezi null a nulou.

ForestCZE
Člen | 209
+
0
-

Marek Bartoš napsal(a):

Uprav si to všude, kde chceš rozlišovat mezi null a nulou.

Jasan. Nakonec jsem to rozdělil do dvou metod a funguje to dobře. Děkuju moc :)

Marek Znojil
Člen | 75
+
0
-

Na yt kanále Nette je fajn přednáška ohledně tohoto tématu:
https://www.youtube.com/watch?…