Skip to content

Commit e056066

Browse files
feature #38996 Remove the default values from setters with a nullable parameter (derrabus, nicolas-grekas)
This PR was merged into the 6.2 branch. Discussion ---------- Remove the default values from setters with a nullable parameter | Q | A | ------------- | --- | Branch? | 6.2 | Bug fix? | no | New feature? | no | Deprecations? | yes | Tickets | N/A | License | MIT | Doc PR | N/A Setters with a default value are a bit odd: I want to set a value, but I won't tell you which one! We do have this kind of setters, like this example from `TokenStorageInterface`: ```php public function setToken(TokenInterface $token = null); ``` This means that those to calls are equivalent: ```php $tokenStorage->setToken(null); $tokenStorage->setToken(); ``` The reason for this is actually a php 5 quirk: On php 5, we did not have nullable parameter type declarations – those we added in php 7.1. The only workaround was to declare `null` as default value because then php would accept passing null despite the type declaration demanding an instance of a specific class/interface. Because the days of php 5 are over, I'd like to change this. Our method signature would then look like this. ```php public function setToken(?TokenInterface $token); ``` We can do this for interfaces and abstract methods because an implementation may add a default value. Thus, removing the default value from the interface alone is not a BC break. For the implementations of that interface, this is a different story because removing the default breaks calling code that omits the parameter entirely. This is why for the implementations I trigger a deprecation if the method is called without arguments. This enables us to remove the default in Symfony 6. This PR performs the suggested changes for `TokenStorageInterface` and `ContainerAwareInterface`, but we have a few more setters like this. But before I continue, I'd like to collect some feedback if this is something you would want to change. Commits ------- 78803b2962 Remove all "nullable-by-default-value" setters 917ffde141 Remove the default values from setters with a nullable parameter.
2 parents 27e4244 + a0c4356 commit e056066

File tree

4 files changed

+71
-1
lines changed

4 files changed

+71
-1
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ CHANGELOG
99
* Add `enum` env var processor
1010
* Add `shuffle` env var processor
1111
* Allow #[When] to be extended
12+
* Change the signature of `ContainerAwareInterface::setContainer()` to `setContainer(?ContainerInterface)`
13+
* Deprecate calling `ContainerAwareTrait::setContainer()` without arguments
1214

1315
6.1
1416
---

ContainerAwareInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ interface ContainerAwareInterface
2121
/**
2222
* Sets the container.
2323
*/
24-
public function setContainer(ContainerInterface $container = null);
24+
public function setContainer(?ContainerInterface $container);
2525
}

ContainerAwareTrait.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ trait ContainerAwareTrait
2525

2626
public function setContainer(ContainerInterface $container = null)
2727
{
28+
if (1 > \func_num_args()) {
29+
trigger_deprecation('symfony/dependency-injection', '6.2', 'Calling "%s::%s()" without any arguments is deprecated, pass null explicitly instead.', __CLASS__, __FUNCTION__);
30+
}
31+
2832
$this->container = $container;
2933
}
3034
}

Tests/ContainerAwareTraitTest.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
16+
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
17+
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
18+
use Symfony\Component\DependencyInjection\ContainerInterface;
19+
20+
class ContainerAwareTraitTest extends TestCase
21+
{
22+
use ExpectDeprecationTrait;
23+
24+
/**
25+
* @group legacy
26+
*/
27+
public function testSetContainerLegacy()
28+
{
29+
$container = $this->createMock(ContainerInterface::class);
30+
31+
$dummy = new ContainerAwareDummy();
32+
$dummy->setContainer($container);
33+
34+
self::assertSame($container, $dummy->getContainer());
35+
36+
$this->expectDeprecation('Since symfony/dependency-injection 6.2: Calling "Symfony\Component\DependencyInjection\Tests\ContainerAwareDummy::setContainer()" without any arguments is deprecated, pass null explicitly instead.');
37+
38+
$dummy->setContainer();
39+
self::assertNull($dummy->getContainer());
40+
}
41+
42+
public function testSetContainer()
43+
{
44+
$container = $this->createMock(ContainerInterface::class);
45+
46+
$dummy = new ContainerAwareDummy();
47+
$dummy->setContainer($container);
48+
49+
self::assertSame($container, $dummy->getContainer());
50+
51+
$dummy->setContainer(null);
52+
self::assertNull($dummy->getContainer());
53+
}
54+
}
55+
56+
class ContainerAwareDummy implements ContainerAwareInterface
57+
{
58+
use ContainerAwareTrait;
59+
60+
public function getContainer(): ?ContainerInterface
61+
{
62+
return $this->container;
63+
}
64+
}

0 commit comments

Comments
 (0)