@@ -126,27 +126,88 @@ protected function generateId(): string
126126 return bin2hex (random_bytes (16 ));
127127 }
128128
129+ /**
130+ * Serialize all properties including child class properties.
131+ * Uses Reflection to capture private/protected properties from child classes.
132+ */
129133 public function __serialize (): array
130134 {
131- return [
132- 'id ' => $ this ->id ,
133- 'queue ' => $ this ->queue ,
134- 'attempts ' => $ this ->attempts ,
135- 'maxAttempts ' => $ this ->maxAttempts ,
136- 'timeout ' => $ this ->timeout ,
137- 'delay ' => $ this ->delay ,
138- 'createdAt ' => $ this ->createdAt ,
139- ];
135+ $ data = [];
136+ $ reflection = new \ReflectionClass ($ this );
137+
138+ // Get all properties from this class and parent classes
139+ do {
140+ foreach ($ reflection ->getProperties () as $ property ) {
141+ $ property ->setAccessible (true );
142+ $ name = $ property ->getName ();
143+
144+ // Skip uninitialized typed properties
145+ if ($ property ->hasType () && !$ property ->isInitialized ($ this )) {
146+ continue ;
147+ }
148+
149+ // Use class name prefix for private properties to avoid conflicts
150+ if ($ property ->isPrivate () && $ property ->getDeclaringClass ()->getName () !== self ::class) {
151+ $ key = $ property ->getDeclaringClass ()->getName () . ':: ' . $ name ;
152+ } else {
153+ $ key = $ name ;
154+ }
155+ $ data [$ key ] = $ property ->getValue ($ this );
156+ }
157+ } while ($ reflection = $ reflection ->getParentClass ());
158+
159+ return $ data ;
140160 }
141161
162+ /**
163+ * Unserialize all properties including child class properties.
164+ */
142165 public function __unserialize (array $ data ): void
143166 {
144- $ this ->id = $ data ['id ' ];
145- $ this ->queue = $ data ['queue ' ];
146- $ this ->attempts = $ data ['attempts ' ];
147- $ this ->maxAttempts = $ data ['maxAttempts ' ];
148- $ this ->timeout = $ data ['timeout ' ];
149- $ this ->delay = $ data ['delay ' ];
150- $ this ->createdAt = $ data ['createdAt ' ];
167+ $ reflection = new \ReflectionClass ($ this );
168+
169+ // Build a map of all properties
170+ $ properties = [];
171+ $ ref = $ reflection ;
172+ do {
173+ foreach ($ ref ->getProperties () as $ property ) {
174+ $ name = $ property ->getName ();
175+ if ($ property ->isPrivate () && $ property ->getDeclaringClass ()->getName () !== self ::class) {
176+ $ key = $ property ->getDeclaringClass ()->getName () . ':: ' . $ name ;
177+ } else {
178+ $ key = $ name ;
179+ }
180+ $ properties [$ key ] = $ property ;
181+ }
182+ } while ($ ref = $ ref ->getParentClass ());
183+
184+ // Restore values from serialized data
185+ foreach ($ data as $ key => $ value ) {
186+ if (isset ($ properties [$ key ])) {
187+ $ properties [$ key ]->setAccessible (true );
188+ $ properties [$ key ]->setValue ($ this , $ value );
189+ }
190+ }
191+
192+ // Initialize any remaining uninitialized typed properties with defaults
193+ foreach ($ properties as $ key => $ property ) {
194+ if ($ property ->hasType () && !$ property ->isInitialized ($ this )) {
195+ $ type = $ property ->getType ();
196+ if ($ type instanceof \ReflectionNamedType && !$ type ->allowsNull ()) {
197+ $ default = match ($ type ->getName ()) {
198+ 'array ' => [],
199+ 'string ' => '' ,
200+ 'int ' => 0 ,
201+ 'float ' => 0.0 ,
202+ 'bool ' => false ,
203+ default => null ,
204+ };
205+ if ($ default !== null ) {
206+ $ property ->setAccessible (true );
207+ $ property ->setValue ($ this , $ default );
208+ }
209+ }
210+ }
211+ }
151212 }
152213}
0 commit comments