If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeLet's try an experiment: In GenusController
, change our var_dump()
to $genus->getFunFact()
: another property on Genus
that should be a string. If you refresh now... it's null! No surprise: we haven't set this yet and that method doesn't have a return type.
declare(strict_types = 1); | |
... line 3 | |
namespace AppBundle\Controller; | |
... lines 5 - 15 | |
class GenusController extends Controller | |
{ | |
... lines 18 - 20 | |
public function typesExampleAction() | |
{ | |
... lines 23 - 25 | |
var_dump($genus->getFunFact()); | |
... line 27 | |
} | |
... lines 29 - 154 | |
} |
Now, add one: : string
. Refresh again.
declare(strict_types = 1); | |
... line 3 | |
namespace AppBundle\Entity; | |
... lines 5 - 17 | |
class Genus | |
{ | |
... lines 20 - 130 | |
public function getFunFact(): string | |
{ | |
return $this->funFact; | |
} | |
... lines 135 - 222 | |
} |
Explosion! This method returns null... which apparently is not a string. This actually made return types a pain in PHP 7... so in PHP 7.1, they fixed it! With "nullable" types. It works like this: if a return type can be null, add a ?
in front of the type.
... lines 1 - 17 | |
class Genus | |
{ | |
... lines 20 - 130 | |
public function getFunFact(): ?string | |
{ | |
return $this->funFact; | |
} | |
... lines 135 - 222 | |
} |
Yep, this method can return a string or null. And once again, life is good!
Let's go further! In the controller, add $genus->setFunFact('This is fun')
then var_dump($genus->getFunFact())
. After, do $genus->setFunFact(null)
... because null should be allowed.
declare(strict_types = 1); | |
... line 3 | |
namespace AppBundle\Controller; | |
... lines 5 - 15 | |
class GenusController extends Controller | |
{ | |
... lines 18 - 20 | |
public function typesExampleAction() | |
{ | |
... lines 23 - 25 | |
$genus->setFunFact('This is fun'); | |
var_dump($genus->getFunFact()); | |
... line 28 | |
$genus->setFunFact(null); | |
... lines 30 - 31 | |
} | |
... lines 33 - 158 | |
} |
Will this work? Totally! It prints the string, then it prints null
. Unless... you type-hint the argument. Right now the argument to setFunFact()
can be anything. Add the string
type-hint.
... lines 2 - 3 | |
namespace AppBundle\Entity; | |
... lines 5 - 17 | |
class Genus | |
{ | |
... lines 20 - 135 | |
public function setFunFact(string $funFact) | |
{ | |
$this->funFact = $funFact; | |
} | |
... lines 140 - 222 | |
} |
No problem, right? Refresh! Ah! The first dump works, but setFunFact(null)
fails. Duh, null is not a string.
With scalar type-hints, we suddenly need to think about things that were never a problem before. That's mostly good, but it's a bit more work. To make this argument nullable, add that same ?
before the type. Without this, passing `null
` as an argument is illegal... in both strict and weak modes.
declare(strict_types = 1); | |
... line 3 | |
namespace AppBundle\Entity; | |
... lines 5 - 17 | |
class Genus | |
{ | |
... lines 20 - 135 | |
public function setFunFact(?string $funFact): void | |
{ | |
... lines 138 - 140 | |
} | |
... lines 142 - 224 | |
} |
Refresh again. Beautiful!
Now, you might be thinking:
Wait, wait wait. How is
?string
different thanstring $funFact = null
?
Hmm, good question! Because if I say string $funFact = null
, that does allow a null value to be passed. In reality, these two syntaxes are almost the same. The difference is that when you default the argument to null, I'm allowed to call setFunFact()
without any arguments: the argument is optional.
But with the nullable, ?string
syntax, the argument is still required... it's simply that null
is a valid value. That makes ?string
better... unless you actually want the argument to be optional.
And by the way, the nullable ?
works for any type, like classes. We'll see that in action next!
"Houston: no signs of life"
Start the conversation!
// composer.json
{
"require": {
"php": ">=5.5.9",
"symfony/symfony": "3.3.*", // v3.3.18
"doctrine/orm": "^2.5", // v2.7.2
"doctrine/doctrine-bundle": "^1.6", // 1.10.3
"doctrine/doctrine-cache-bundle": "^1.2", // 1.3.2
"symfony/swiftmailer-bundle": "^2.3", // v2.5.4
"symfony/monolog-bundle": "^2.8", // v2.12.1
"symfony/polyfill-apcu": "^1.0", // v1.3.0
"sensio/distribution-bundle": "^5.0", // v5.0.19
"sensio/framework-extra-bundle": "^3.0.2", // v3.0.25
"incenteev/composer-parameter-handler": "^2.0", // v2.1.2
"knplabs/knp-markdown-bundle": "^1.4", // 1.5.1
"doctrine/doctrine-migrations-bundle": "^1.1", // v1.2.1
"stof/doctrine-extensions-bundle": "^1.2", // v1.2.2
"composer/package-versions-deprecated": "^1.11" // 1.11.99
},
"require-dev": {
"sensio/generator-bundle": "^3.0", // v3.1.4
"symfony/phpunit-bridge": "^3.0", // v3.2.8
"nelmio/alice": "^2.1", // v2.3.1
"doctrine/doctrine-fixtures-bundle": "^2.3", // v2.4.1
"symfony/web-server-bundle": "3.3.*"
}
}