Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions UPGRADE-7.4.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ HttpFoundation

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

HttpKernel
----------

* Deprecate implementing `__sleep/wakeup()` on kernels; use `__(un)serialize()` instead
* Deprecate implementing `__sleep/wakeup()` on data collectors; use `__(un)serialize()` instead
* Make `Profile` final and `Profiler::__sleep()` internal

Security
--------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@

use Symfony\Bundle\WebProfilerBundle\Profiler\TemplateManager;
use Symfony\Bundle\WebProfilerBundle\Tests\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\Profiler\Profile;
use Symfony\Component\HttpKernel\Profiler\Profiler;
Expand Down Expand Up @@ -57,7 +60,10 @@ public function testGetNameValidTemplate()
->withAnyParameters()
->willReturnCallback($this->profilerHasCallback(...));

$this->assertEquals('@Foo/Collector/foo.html.twig', $this->templateManager->getName(new ProfileDummy(), 'foo'));
$profile = new Profile('token');
$profile->addCollector(new DummyCollector('foo'));
$profile->addCollector(new DummyCollector('bar'));
$this->assertEquals('@Foo/Collector/foo.html.twig', $this->templateManager->getName($profile, 'foo'));
}

public function profilerHasCallback($panel)
Expand Down Expand Up @@ -94,19 +100,18 @@ protected function mockTwigEnvironment()
}
}

class ProfileDummy extends Profile
class DummyCollector extends DataCollector
{
public function __construct()
public function __construct(private string $name)
{
parent::__construct('token');
}

public function hasCollector(string $name): bool
public function getName(): string
{
return $this->name;
}

public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
return match ($name) {
'foo',
'bar' => true,
default => false,
};
}
}
7 changes: 7 additions & 0 deletions src/Symfony/Component/HttpKernel/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
CHANGELOG
=========

7.4
---

* Deprecate implementing `__sleep/wakeup()` on kernels; use `__(un)serialize()` instead
* Deprecate implementing `__sleep/wakeup()` on data collectors; use `__(un)serialize()` instead
* Make `Profile` final and `Profiler::__sleep()` internal

7.3
---

Expand Down
55 changes: 48 additions & 7 deletions src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,67 @@
] + ReflectionCaster::UNSET_CLOSURE_FILE_INFO;
}

public function __sleep(): array
public function __serialize(): array
{
return ['data'];
if (self::class === (new \ReflectionMethod($this, '__sleep'))->class) {
return ['data' => $this->data];
}

trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this));

$data = [];
foreach ($this->__sleep() as $key) {
try {
if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) {
$data[$key] = $r->getValue($this);
}
} catch (\ReflectionException) {
$data[$key] = $this->$key;
}
}

return $data;
}

public function __wakeup(): void
public function __unserialize(array $data): void
{
if (self::class !== (new \ReflectionMethod($this, '__wakeup'))->class) {
trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__wakeup()" is deprecated, use "__unserialize()" instead.', get_debug_type($this));
}

if (\in_array(array_keys($data), [['data'], ["\0*\0data"]], true)) {
$this->data = $data['data'] ?? $data["\0*\0data"];

return;
}

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));

\Closure::bind(function ($data) {
foreach ($data as $key => $value) {
$this->{("\0" === $key[0] ?? '') ? substr($key, 1 + strrpos($key, "\0")) : $key} = $value;

Check failure on line 125 in src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php:125:26: InvalidArgument: Isset only works with variables and array elements (see https://psalm.dev/004)

Check failure on line 125 in src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php:125:26: InvalidArgument: Isset only works with variables and array elements (see https://psalm.dev/004)
}

$this->__wakeup();
}, $this, static::class)($data);
}

/**
* @internal to prevent implementing \Serializable
* @internal since Symfony 7.4, will be removed in 8.0
*
* @final since Symfony 7.4, will be removed in 8.0
*/
final protected function serialize(): void
public function __sleep(): array
{
return ['data'];
}

/**
* @internal to prevent implementing \Serializable
* @internal since Symfony 7.4, will be removed in 8.0
*
* @final since Symfony 7.4, will be removed in 8.0
*/
final protected function unserialize(string $data): void
public function __wakeup(): void
{
}

Expand Down
59 changes: 59 additions & 0 deletions src/Symfony/Component/HttpKernel/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -775,11 +775,70 @@
return $container;
}

public function __serialize(): array
{
if (self::class === (new \ReflectionMethod($this, '__sleep'))->class) {
return [
'environment' => $this->environment,
'debug' => $this->debug,
];
}

trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__sleep()" is deprecated, use "__serialize()" instead.', get_debug_type($this));

$data = [];
foreach ($this->__sleep() as $key) {
try {
if (($r = new \ReflectionProperty($this, $key))->isInitialized($this)) {
$data[$key] = $r->getValue($this);
}
} catch (\ReflectionException) {
$data[$key] = $this->$key;
}
}

return $data;
}

public function __unserialize(array $data): void
{
if (self::class !== (new \ReflectionMethod($this, '__wakeup'))->class) {
trigger_deprecation('symfony/http-kernel', '7.4', 'Implementing "%s::__wakeup()" is deprecated, use "__unserialize()" instead.', get_debug_type($this));
}

if (\in_array(array_keys($data), [['environment', 'debug'], ["\0*\0environment", "\0*\0debug"]], true)) {
$this->environment = $data['environment'] ?? $data["\0*\0environment"];
$this->debug = $data['debug'] ?? $data["\0*\0debug"];

return;
}

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));

\Closure::bind(function ($data) {
foreach ($data as $key => $value) {
$this->{("\0" === $key[0] ?? '') ? substr($key, 1 + strrpos($key, "\0")) : $key} = $value;

Check failure on line 820 in src/Symfony/Component/HttpKernel/Kernel.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/HttpKernel/Kernel.php:820:26: InvalidArgument: Isset only works with variables and array elements (see https://psalm.dev/004)

Check failure on line 820 in src/Symfony/Component/HttpKernel/Kernel.php

View workflow job for this annotation

GitHub Actions / Psalm

InvalidArgument

src/Symfony/Component/HttpKernel/Kernel.php:820:26: InvalidArgument: Isset only works with variables and array elements (see https://psalm.dev/004)
}

$this->__wakeup();
}, $this, static::class)($data);
}

/**
* @internal since Symfony 7.4, will be removed in 8.0
*
* @final since Symfony 7.4, will be removed in 8.0
*/
public function __sleep(): array
{
return ['environment', 'debug'];
}

/**
* @internal since Symfony 7.4, will be removed in 8.0
*
* @final since Symfony 7.4, will be removed in 8.0
*/
public function __wakeup(): void
{
if (\is_object($this->environment) || \is_object($this->debug)) {
Expand Down
7 changes: 5 additions & 2 deletions src/Symfony/Component/HttpKernel/Profiler/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface;

/**
* Profile.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @final since Symfony 7.4
*/
class Profile
{
Expand Down Expand Up @@ -248,6 +248,9 @@ public function hasCollector(string $name): bool
return isset($this->collectors[$name]);
}

/**
* @internal since Symfony 7.4, will be replaced by `__serialize()` in 8.0
*/
public function __sleep(): array
{
return ['token', 'parent', 'children', 'collectors', 'ip', 'method', 'url', 'time', 'statusCode', 'virtualType'];
Expand Down
2 changes: 1 addition & 1 deletion src/Symfony/Component/HttpKernel/Tests/KernelTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ public function testSerialize()
$env = 'test_env';
$debug = true;
$kernel = new KernelForTest($env, $debug);
$expected = \sprintf("O:48:\"%s\":2:{s:14:\"\0*\0environment\";s:8:\"test_env\";s:8:\"\0*\0debug\";b:1;}", KernelForTest::class);
$expected = \sprintf('O:48:"%s":2:{s:11:"environment";s:8:"test_env";s:5:"debug";b:1;}', KernelForTest::class);
$this->assertEquals($expected, serialize($kernel));
}

Expand Down
Loading