Page 2 of 2

Re: What is the best PHP equivalent of the "transient" keywo

Posted: Sun Oct 02, 2011 10:20 pm
by Weirdan
This _sleep() method cannot return any private value for a parent.
It can. You have to prefix it with <null><classname><null> sequence:

Code: Select all

    <?php
    class A
    {
        private $_q = 10;
    }
    class B extends A
    {
        private $_qq = 20;
        public function __sleep()
        {
            return array('_qq', "\0A\0_q");
        }
    }

    $q = new B;
    $e = unserialize(serialize($q));
    var_dump($q, $e);
I wouldn't use this approach though as it's, frankly, a hack relying on knowledge of the internal representation of objects, but nevertheless it's possible.

Re: What is the best PHP equivalent of the "transient" keywo

Posted: Sun Oct 02, 2011 11:36 pm
by Benjamin
How did you figure this out?

Re: What is the best PHP equivalent of the "transient" keywo

Posted: Mon Oct 03, 2011 1:12 am
by Weirdan
Benjamin wrote:How did you figure this out?
I knew there was a way to get access to private variables of an object by casting the object to array and using this null notation. I figured it was worth a try to use this in __sleep() - turned out it works there as well.

I thought this casting hack would no longer work, but now that I tested it it still works in PHP 5.3.7 (debian flavor).

Re: What is the best PHP equivalent of the "transient" keywo

Posted: Mon Oct 03, 2011 1:16 am
by Benjamin
Is this a side effect of how PHP stores objects internally or was it added intentionally in order to aid in unit-testing or debugging?

Did you dig around in the code?

Re: What is the best PHP equivalent of the "transient" keywo

Posted: Mon Oct 03, 2011 1:26 am
by Weirdan
This is a side effect as far as I know. I didn't dig the php source, but I think I read Sebastian considered using it in PHPUnit before ReflectionProperty::setAccessible() was introduced.

Re: What is the best PHP equivalent of the "transient" keywo

Posted: Mon Oct 03, 2011 1:47 am
by Weirdan
Works in 5.3.8 as well.

Re: What is the best PHP equivalent of the "transient" keywo

Posted: Tue Apr 17, 2012 1:43 pm
by x_mutatis_mutandis_x
:idea: Check this out, this is what I use:

Code: Select all


class PHPObject implements Serializable {

	private $transientVar = 40;

	/**
	 * The inner property map that contains the serializable data.
	 * Un serializable objects cannot be stored in here.
	 *
	 * @var array
	 */
	private $data = array();

	/**
	 * Constructor
	 *
	 * @param mixed $data
	 * @return unknown_type
	 */
	public function __construct($data = array())
	{
		if (empty($data)) {
			$this->data = array();

		} else if (is_array($data)) {
			$this->data = $data;

		} else if (is_object($data) && $data instanceof stdClass) {
			$this->data = (array) $data;

		} 

                                //lost when unserialized 
		$this->transientVar = 100;
	}

	/**
	 * Magic method facilitating access to private properties
	 * to set value to the property identified by its name
	 *
	 * @param string $name	the property name
	 * @param mixed $value	the value to be set
	 */
	public function __set($name, $value)
	{
		$this->data[$name] = $value;
	}

	/**
	 * Magic method facilitating access to private properties
	 * returning the property value associated with a property name
	 *
	 * @param string $name	the property name
	 * @return mixed	the value held by this property
	 */
	public function __get($name)
	{

		if ($this->__isset($name)) {
			return $this->data[$name];
		}

		return null;
	}

	/**
	 * Magic method that unsets a property; Property will still
	 * exist but will be undeclared
	 *
	 * @param string $name	the property name
	 */
	public function __unset($name)
	{
		if ($this->__isset($name)) {
			unset($this->data[$name]);
		}
	}

	/**
	 * Magic method that checks if the property is declared for
	 * this bean instance
	 *
	 * @param string $name	the property name
	 * @return boolean	true if property exists and declared
	 * 					else false
	 */
	public function __isset($name)
	{
		return array_key_exists($name, $this->data);
	}

	/**
	 * String representation of an object
	 *
	 * @return string	the object respresented as a string
	 */
	public function __toString()
	{
		return get_class($this) . hashcode();
	}

	/**
	 * This function is called prior to serialization of an object
                 * @deprecated
	 */
	public function __sleep()
	{}

	/**
	 * This function is called after unserialization of an object
                 * @deprecated
	 */
	public function __wakeup()
	{}

	/**
	 * Equality test.
	 * Default implementatio is object identity test.
	 *
	 * @param object $obj other object
	 * @return bool true if this object and the other object are the same instance.
	 */
	public function equals($obj)
	{
		return $this === $obj;
	}


	/**
	 * Returns object ID hash code.
	 * This return value is available on PHP 5.2.0 or later.
	 *
	 * @return string object hash code
	 */
	public function hashCode()
	{
		return System::identityHashCode($this);
	}

	/**
	 * (non-PHPdoc)
	 * @see Serializable::serialize()
	 */
	public function serialize()
	{
		return serialize($this->data);
	}

	/**
	 * (non-PHPdoc)
	 * @see Serializable::unserialize()
	 */
	public function unserialize($str)
	{
		$this->data = unserialize($str);
	}


}


Treat this as java.lang.Object and extend it everywhere in your hirearchy, and bingo. Magic methods to your rescue.

If you want the object as a whole to be not serializable, override serialize() and unserialize() [no recommended], or use a marker interface like java.io.Serializable.

Criticism very welcomed..