Doctrine Common
  1. Doctrine Common
  2. DCOM-175

Proxies return private properties in __sleep, which is not supported by PHP.

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.4
    • Fix Version/s: 2.5.0
    • Component/s: None
    • Labels:
      None

      Description

      __sleep should not return private parent property names (see http://php.net/__sleep) this raises notices, and also results in the value of the property being 'N' (null) instead of keeping its value.

      I am unfortunately stuck having to serialize proxies in my revision tracking, as doctrine seems to be currently ignoring the fetch="EAGER" I set on the related properties.

      Proxies should use the Serializable interface, and not __sleep, or not return parent property names which are private, it serves no purpose, and is not supported by PHP itself anyway.

      Also, if you keep __sleep, but do not return the parent property names, then it will only include the items you return, so it would be better to simply drop the __sleep method, I cannot actually see any useful purpose it serves.

        Activity

        Hide
        Ryan Mauger added a comment -

        just updated the issue body, realised that I worded something badly.

        Show
        Ryan Mauger added a comment - just updated the issue body, realised that I worded something badly.
        Hide
        Marco Pivetta added a comment -

        Ryan Mauger I think that's a limitation we have. We use `__sleep` to avoid serializing fields like the initializers and the persisters of course.

        Even by implementing serializable, it would only work if the end user implemented it in the parent class.

        Tempted to mark it as "can't fix"

        Show
        Marco Pivetta added a comment - Ryan Mauger I think that's a limitation we have. We use `__sleep` to avoid serializing fields like the initializers and the persisters of course. Even by implementing serializable, it would only work if the end user implemented it in the parent class. Tempted to mark it as "can't fix"
        Hide
        Marco Pivetta added a comment - - edited

        I think there's a solution by having something like following:

        class SomeGeneratedProxyName extends RealName implements \Serializable
        {
            public function unserialize($data)
            {
                $reflectionClass = new ReflectionClass($this);
                foreach ($reflectionClass->getProperties(ReflectionProperty::IS_PRIVATE) as $privateProp) {
                    $privateProp->setAccessible(true);
                    $privateProp->setValue($this, $data[$privateProp->getName()]);
                }
                // ... other props ...
            }
        
            public function serialize()
            {
                $data = array();
                $reflectionClass = new ReflectionClass($this);
                foreach ($reflectionClass->getProperties(ReflectionProperty::IS_PRIVATE) as $privateProp) {
                    $privateProp->setAccessible(true);
                    $data[$privateProp->getName()] = $privateProp->getValue($this);
                }
                // ... other props ...
                return $data;
            }
        }
        
        Show
        Marco Pivetta added a comment - - edited I think there's a solution by having something like following: class SomeGeneratedProxyName extends RealName implements \Serializable { public function unserialize($data) { $reflectionClass = new ReflectionClass($ this ); foreach ($reflectionClass->getProperties(ReflectionProperty::IS_PRIVATE) as $privateProp) { $privateProp->setAccessible( true ); $privateProp->setValue($ this , $data[$privateProp->getName()]); } // ... other props ... } public function serialize() { $data = array(); $reflectionClass = new ReflectionClass($ this ); foreach ($reflectionClass->getProperties(ReflectionProperty::IS_PRIVATE) as $privateProp) { $privateProp->setAccessible( true ); $data[$privateProp->getName()] = $privateProp->getValue($ this ); } // ... other props ... return $data; } }
        Hide
        Marco Pivetta added a comment - - edited

        Ryan Mauger I started implementing this one at https://github.com/Ocramius/common/compare/hotfix;DCOM-175 and so far it looks promising.

        The only doubts so far are with handling cases like following:

        class MyEntity implements Serializable
        {
            public function serialize()
            {
                // [...]
            }
        
            public function unserialize($serialized)
            {
                // [...]
            }
        
            public function __sleep()
            {
                // [...]
            }
        
            public function __wakeup()
            {
                // [...]
            }
        }
        

        So far I didn't get to write tests that demonstrate the exact behaviour for this case, but it looks like when `Serializable` is implemented, `_sleep` and `_wakeup` are ignored. Any thoughts on this?

        Show
        Marco Pivetta added a comment - - edited Ryan Mauger I started implementing this one at https://github.com/Ocramius/common/compare/hotfix;DCOM-175 and so far it looks promising. The only doubts so far are with handling cases like following: class MyEntity implements Serializable { public function serialize() { // [...] } public function unserialize($serialized) { // [...] } public function __sleep() { // [...] } public function __wakeup() { // [...] } } So far I didn't get to write tests that demonstrate the exact behaviour for this case, but it looks like when `Serializable` is implemented, `_ sleep` and ` _wakeup` are ignored. Any thoughts on this?
        Hide
        Marco Pivetta added a comment -

        A possible solution is to use something like http://eval.in/16806, and thus exploiting the ability of php to retrieve an object's private properties by using the special

        chr(0) . 'Foo' . chr(0) . 'bar'
        

        trick.

        This can be abstracted by using

        array_keys((array) $object);

        , which retrieves also those special keys

        Show
        Marco Pivetta added a comment - A possible solution is to use something like http://eval.in/16806 , and thus exploiting the ability of php to retrieve an object's private properties by using the special chr(0) . 'Foo' . chr(0) . 'bar' trick. This can be abstracted by using array_keys((array) $object); , which retrieves also those special keys
        Hide
        Marco Pivetta added a comment -
        Show
        Marco Pivetta added a comment - Provided a fix at https://github.com/doctrine/common/pull/284
        Show
        Marco Pivetta added a comment - Solved at https://github.com/doctrine/common/commit/9c6b8615a988117dec83bdbb0fad80afef23eab8

          People

          • Assignee:
            Marco Pivetta
            Reporter:
            Ryan Mauger
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: