Skip to content

Commit c54120e

Browse files
[HttpKernel] Deprecate __sleep/wakeup() on kernels and data collectors and make Profile final
1 parent b130cee commit c54120e

File tree

7 files changed

+142
-20
lines changed

7 files changed

+142
-20
lines changed

UPGRADE-7.4.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ HttpFoundation
5252

5353
* Deprecate using `Request::sendHeaders()` after headers have already been sent; use a `StreamedResponse` instead
5454

55+
HttpKernel
56+
----------
57+
58+
* Deprecate implementing `__sleep/wakeup()` on kernels; use `__(un)serialize()` instead
59+
* Deprecate implementing `__sleep/wakeup()` on data collectors; use `__(un)serialize()` instead
60+
* Make `Profile` final and `Profiler::__sleep()` internal
61+
5562
Security
5663
--------
5764

src/Symfony/Bundle/WebProfilerBundle/Tests/Profiler/TemplateManagerTest.php

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
use Symfony\Bundle\WebProfilerBundle\Profiler\TemplateManager;
1515
use Symfony\Bundle\WebProfilerBundle\Tests\TestCase;
16+
use Symfony\Component\HttpFoundation\Request;
17+
use Symfony\Component\HttpFoundation\Response;
18+
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
1619
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
1720
use Symfony\Component\HttpKernel\Profiler\Profile;
1821
use Symfony\Component\HttpKernel\Profiler\Profiler;
@@ -57,7 +60,10 @@ public function testGetNameValidTemplate()
5760
->withAnyParameters()
5861
->willReturnCallback($this->profilerHasCallback(...));
5962

60-
$this->assertEquals('@Foo/Collector/foo.html.twig', $this->templateManager->getName(new ProfileDummy(), 'foo'));
63+
$profile = new Profile('token');
64+
$profile->addCollector(new DummyCollector('foo'));
65+
$profile->addCollector(new DummyCollector('bar'));
66+
$this->assertEquals('@Foo/Collector/foo.html.twig', $this->templateManager->getName($profile, 'foo'));
6167
}
6268

6369
public function profilerHasCallback($panel)
@@ -94,19 +100,18 @@ protected function mockTwigEnvironment()
94100
}
95101
}
96102

97-
class ProfileDummy extends Profile
103+
class DummyCollector extends DataCollector
98104
{
99-
public function __construct()
105+
public function __construct(private string $name)
100106
{
101-
parent::__construct('token');
102107
}
103108

104-
public function hasCollector(string $name): bool
109+
public function getName(): string
110+
{
111+
return $this->name;
112+
}
113+
114+
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
105115
{
106-
return match ($name) {
107-
'foo',
108-
'bar' => true,
109-
default => false,
110-
};
111116
}
112117
}

src/Symfony/Component/HttpKernel/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
CHANGELOG
22
=========
33

4+
7.4
5+
---
6+
7+
* Deprecate implementing `__sleep/wakeup()` on kernels; use `__(un)serialize()` instead
8+
* Deprecate implementing `__sleep/wakeup()` on data collectors; use `__(un)serialize()` instead
9+
* Make `Profile` final and `Profiler::__sleep()` internal
10+
411
7.3
512
---
613

src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,26 +84,67 @@ protected function getCasters(): array
8484
] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO;
8585
}
8686

87-
public function __sleep(): array
87+
public function __serialize(): array
8888
{
89-
return ['data'];
89+
if (self::class === (new \ReflectionMethod($this, '__sleep'))->class) {
90+
return ['data' => $this->data];
91+
}
92+
93+
trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this));
94+
95+
$data = [];
96+
foreach ($this->__sleep() as $key) {
97+
try {
98+
if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) {
99+
$data[$key] = $r->getValue($this);
100+
}
101+
} catch (\ReflectionException) {
102+
$data[$key] = $this->$key;
103+
}
104+
}
105+
106+
return $data;
90107
}
91108

92-
public function __wakeup(): void
109+
public function __unserialize(array $data): void
93110
{
111+
if (self::class !== (new \ReflectionMethod($this, '__wakeup'))->class) {
112+
trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__wakeup()" is deprecated, use "__unserialize()" instead.', get_debug_type($this));
113+
}
114+
115+
if (\in_array(array_keys($data), [['data'], ["\0*\0data"]], true)) {
116+
$this->data = $data['data'] ?? $data["\0*\0data"];
117+
118+
return;
119+
}
120+
121+
trigger_deprecation('symfony/http-kernel', '7.4', 'Passing more than just key "data" to "%s::__unserialize()" is deprecated, populate properties in "%s::__unserialize()" instead.', self::class, get_debug_type($this));
122+
123+
\Closure::bind(function ($data) {
124+
foreach ($data as $key => $value) {
125+
$this->{("\0" === $key[0] ?? '') ? substr($key, 1 + strrpos($key, "\0")) : $key} = $value;
126+
}
127+
128+
$this->__wakeup();
129+
}, $this, static::class)($data);
94130
}
95131

96132
/**
97-
* @internal to prevent implementing \Serializable
133+
* @internal since Symfony 7.4, will be removed in 8.0
134+
*
135+
* @final since Symfony 7.4, will be removed in 8.0
98136
*/
99-
final protected function serialize(): void
137+
public function __sleep(): array
100138
{
139+
return ['data'];
101140
}
102141

103142
/**
104-
* @internal to prevent implementing \Serializable
143+
* @internal since Symfony 7.4, will be removed in 8.0
144+
*
145+
* @final since Symfony 7.4, will be removed in 8.0
105146
*/
106-
final protected function unserialize(string $data): void
147+
public function __wakeup(): void
107148
{
108149
}
109150

src/Symfony/Component/HttpKernel/Kernel.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,11 +775,70 @@ private function preBoot(): ContainerInterface
775775
return $container;
776776
}
777777

778+
public function __serialize(): array
779+
{
780+
if (self::class === (new \ReflectionMethod($this, '__sleep'))->class) {
781+
return [
782+
'environment' => $this->environment,
783+
'debug' => $this->debug,
784+
];
785+
}
786+
787+
trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this));
788+
789+
$data = [];
790+
foreach ($this->__sleep() as $key) {
791+
try {
792+
if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) {
793+
$data[$key] = $r->getValue($this);
794+
}
795+
} catch (\ReflectionException) {
796+
$data[$key] = $this->$key;
797+
}
798+
}
799+
800+
return $data;
801+
}
802+
803+
public function __unserialize(array $data): void
804+
{
805+
if (self::class !== (new \ReflectionMethod($this, '__wakeup'))->class) {
806+
trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__wakeup()" is deprecated, use "__unserialize()" instead.', get_debug_type($this));
807+
}
808+
809+
if (\in_array(array_keys($data), [['environment', 'debug'], ["\0*\0environment", "\0*\0debug"]], true)) {
810+
$this->environment = $data['environment'] ?? $data["\0*\0environment"];
811+
$this->debug = $data['debug'] ?? $data["\0*\0debug"];
812+
813+
return;
814+
}
815+
816+
trigger_deprecation('symfony/http-kernel', '7.4', 'Passing more than just key "environment" and "debug" to "%s::__unserialize()" is deprecated, populate properties in "%s::__unserialize()" instead.', self::class, get_debug_type($this));
817+
818+
\Closure::bind(function ($data) {
819+
foreach ($data as $key => $value) {
820+
$this->{("\0" === $key[0] ?? '') ? substr($key, 1 + strrpos($key, "\0")) : $key} = $value;
821+
}
822+
823+
$this->__wakeup();
824+
}, $this, static::class)($data);
825+
}
826+
827+
/**
828+
* @internal since Symfony 7.4, will be removed in 8.0
829+
*
830+
* @final since Symfony 7.4, will be removed in 8.0
831+
*/
778832
public function __sleep(): array
779833
{
780834
return ['environment', 'debug'];
781835
}
782836

837+
/**
838+
* @internal since Symfony 7.4, will be removed in 8.0
839+
*
840+
* @final since Symfony 7.4, will be removed in 8.0
841+
*/
783842
public function __wakeup(): void
784843
{
785844
if (\is_object($this->environment) || \is_object($this->debug)) {

src/Symfony/Component/HttpKernel/Profiler/Profile.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;
1515

1616
/**
17-
* Profile.
18-
*
1917
* @author Fabien Potencier <[email protected]>
18+
*
19+
* @final since Symfony 7.4
2020
*/
2121
class Profile
2222
{
@@ -248,6 +248,9 @@ public function hasCollector(string $name): bool
248248
return isset($this->collectors[$name]);
249249
}
250250

251+
/**
252+
* @internal since Symfony 7.4, will be replaced by `__serialize()` in 8.0
253+
*/
251254
public function __sleep(): array
252255
{
253256
return ['token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode', 'virtualType'];

src/Symfony/Component/HttpKernel/Tests/KernelTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ public function testSerialize()
246246
$env = 'test_env';
247247
$debug = true;
248248
$kernel = new KernelForTest($env, $debug);
249-
$expected = \sprintf("O:48:\"%s\":2:{s:14:\"\0*\0environment\";s:8:\"test_env\";s:8:\"\0*\0debug\";b:1;}", KernelForTest::class);
249+
$expected = \sprintf('O:48:"%s":2:{s:11:"environment";s:8:"test_env";s:5:"debug";b:1;}', KernelForTest::class);
250250
$this->assertEquals($expected, serialize($kernel));
251251
}
252252

0 commit comments

Comments
 (0)