diff --git a/.styleci.yml b/.styleci.yml index 05af66632431..f32a07e6c2ad 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -4,6 +4,7 @@ php: finder: not-name: - bad-syntax-strategy.php + - "*ExcludedFromStyleCiTest.php" js: finder: exclude: diff --git a/src/Illuminate/Database/Eloquent/Model.php b/src/Illuminate/Database/Eloquent/Model.php index 90260a57ca32..3ed36188ebbb 100644 --- a/src/Illuminate/Database/Eloquent/Model.php +++ b/src/Illuminate/Database/Eloquent/Model.php @@ -2584,18 +2584,25 @@ public function escapeWhenCastingToString($escape = true) /** * Prepare the object for serialization. * - * @return array + * @return string[] */ - public function __sleep() + public function __serialize(): array { $this->mergeAttributesFromCachedCasts(); - $this->classCastCache = []; - $this->attributeCastCache = []; - $this->relationAutoloadCallback = null; - $this->relationAutoloadContext = null; + // When serializing the model, we may accidentally catch up some virtual properties. + // We will transform the instance to an array to skip them, and then we will remove + // the model caches so those values are not serialized with the rest of the model. + $props = get_mangled_object_vars($this); + + unset( + $props["\0*\0classCastCache"], + $props["\0*\0attributeCastCache"], + $props["\0*\0relationAutoloadCallback"], + $props["\0*\0relationAutoloadContext"], + ); - return array_keys(get_object_vars($this)); + return $props; } /** diff --git a/tests/Database/DatabaseEloquentSerializationExcludedFromStyleCiTest.php b/tests/Database/DatabaseEloquentSerializationExcludedFromStyleCiTest.php new file mode 100644 index 000000000000..0782e37b984d --- /dev/null +++ b/tests/Database/DatabaseEloquentSerializationExcludedFromStyleCiTest.php @@ -0,0 +1,55 @@ +markTestSkipped('Requires Virtual Properties.'); + } + + $model = new EloquentModelWithVirtualPropertiesStub(); + $model->foo = 'bar'; + + $serialized = serialize($model); + + $this->assertStringNotContainsString('virtualGet', $serialized); + $this->assertStringNotContainsString('virtualSet', $serialized); + + // Ensure attributes and protected normal attributes are also serialized. + $this->assertStringContainsString('foo', $serialized); + $this->assertStringContainsString('bar', $serialized); + $this->assertStringContainsString('isVisible', $serialized); + $this->assertStringContainsString('yes', $serialized); + } +} + +if (version_compare(PHP_VERSION, '8.4.0-dev', '>=')) { + eval(<<<'PHP' +namespace Illuminate\Tests\Database; + +use Illuminate\Database\Eloquent\Model; + +class EloquentModelWithVirtualPropertiesStub extends Model +{ + public $virtualGet { + get => $this->foo; + } + + public $virtualSet { + get => $this->foo; + set { + // + } + } + + protected $isVisible = 'yes'; +} + +PHP + ); +}