Cloning objects results in 500 internal server error

Anyone else experiencing the same problem? I got it whenever I try to clone objects, and never understood why this keeps happening.

Could this be the cause of error? All my classes extend from the root Object class, which has this __clone() method:


    /**
     * Magic method __clone() for Object Class, returns a copy of Object with additional operations.
     * @access public
     * @return Object
     */
    public function __clone(){
        return clone $this;
    }

Maybe this is redundant, but still it does not explain why a 500 Internal Server Error is triggered. I thought it might throw a fatal error if the syntax is incorrect or that the operation is invalid. sigh

Do you have a real basic example of a class that inherits this Object class that performs the 500 internal server error? I’d be willing to try it out on one of my servers if you have reproducible code (otherwise, I’d just be guessing at what the problem may be…).

According to the manual:

Once the cloning is complete, if a __clone() method is defined, then the newly created object’s __clone() method will be called, to allow any necessary properties that need to be changed.

This being the case, if you call clone $this; in your __clone method, isn’t it going to end up in some kind of infinite loop?

fretburner is spot on. __clone() is called AFTER the object has been cloned, not before. __clone will be called on the newly created object, not the object you’re cloning before it gets cloned so every time you clone an object, it gets cloned again (And then that gets cloned, and that, ad infinitum)

So you are saying that what I am doing is actually creating an infinite loop? Oh my…

Exactly. And I’m fairly sure the return vale of __clone is never used at all.

I see, I thought __clone() works like Java’s clone() method on the object you operate. Thanks for letting me know, I will run another test again and hopefully wont run into another 500 Internal Server Error.

Update:
It wont work even if I remove ‘return clone $this;’ from the script, still 500 Internal Server error, and the speed is rather fast so I dont think it has anything to do with infinite loop this time. Weird, maybe I should try removing the magic method __clone() for good? Even an empty __clone() doesnt fix the issue.

Update 2:
It works if I completely get rid of the __clone() method from the interface that specifes a clonable contract. Weird though, is the presence of method __clone() in the interface causing all the trouble?

Hmm, strange. Can you post a minimalist example, one interface, one class that implements it and the code you’re using to clone the object?

edit: this works for me:


<?php

interface A {
	public function __clone();
}

class B implements A {
	public function __clone() {
		
	}
}

$b = new B;
$b2 = clone $b;

var_dump($b2);

?>

I have no idea tbh, removing __clone() method completely from both the abstract root class and the interface will work, but leaving a marker __clone() method always result in 500 internal server error. Perhaps the method __clone() is not working properly on my server?

No, it’s almost certainly something else. Can you post a cut down version of your code? Just the class chain, and __clone methods (Whereever they are)

Well the class hierachy is a bit complex, but anyway I will give a try:

Interface: Objective


<?php

namespace Resource\\Native;

/**
 * The Objective Interface, it is the interface that all Mysidia classes should implement minus a few special cases.
 * It defines a standard interface for Mysidia Objects, the root class Object also implements this interface.
 * This interface is very useful for classes that extend from PHP's built-in classes, as they cannot extend from root Object Class.
 * By Implementing Objective interface, objects of the specific class can be used in Collections Framework.
 * @category Resource
 * @package Native
 * @author Hall of Famer 
 * @copyright Mysidia Adoptables Script
 * @link http://www.mysidiaadoptables.com
 * @since 1.3.3
 * @todo Not much at this point.
 *
 */
 
interface Objective{

    /**
     * The equals method, checks whether target object is equivalent to this one.
     * @param Objective  $object	 
     * @access public
     * @return Boolean
     */
    public function equals(Objective $object);
	
    /**
     * The getClassName method, returns class name of an instance. 
	 * The return value may differ depending on child classes. 
     * @access public
     * @return String
     */	
    public function getClassName();
	
    /**
     * Magic method __clone() for Object Class, returns a copy of Object with additional operations.
     * @access public
     * @return Object
     */
	public function __clone();
	
    /**
     * Magic method to_String() for Object class, returns object information.
     * @access public
     * @return String
     */	
	public function __toString(); 
}
?>

Abstract Class: Object


<?php

namespace Resource\\Native;

/**
 * The Abstract Object Class, root of all Mysidia library files.
 * Contrary to Java's Object root class, this one is abstract.
 * For this reason, one cannot instantiate an object of this class.
 * @category Resource
 * @package Native
 * @author Hall of Famer 
 * @copyright Mysidia Adoptables Script
 * @link http://www.mysidiaadoptables.com
 * @since 1.3.2
 * @todo Not much at this point.
 * @abstract
 *
 */

abstract class Object implements Objective{
  
    /**
     * Constructor of Object Class, which simply serves as a marker for child classes.
     * @access public
     * @return Void
     */
    public function __construct(){

    }

	/**
     * Destructor of Object Class, which simply serves as a marker for child classes.
     * @access public
     * @return Void
     */
    public function __destruct(){

    }

    /**
     * Magic method __clone() for Object Class, returns a copy of Object with additional operations.
     * @access public
     * @return Object
     */
    public function __clone(){

    }
 
    /**
     * The getClassName method, returns class name of an instance. 
	 * It is alias to getClass method, its existence is for backward compatibility.
     * @access public
     * @return String
     */
    public function getClassName(){
        return $this->getClass();
    }
 
    /**
     * The equals method, checks whether target object is equivalent to this one.
     * @param Objective  $object	 
     * @access public
     * @return Boolean
     */
    public function equals(Objective $object){
        return ($this == $object);
    } 

	/**
     * The hashCode method, returns the hash code for the very Object.
     * @access public
     * @return Int
     */			
    public function hashCode(){
	    return hexdec(spl_object_hash($this));
    }

    /**
     * The hasMethod method, examines if the object has a certain method.
     * @param String  $method
     * @access public
     * @return Boolean
     */	
	public function hasMethod($method){
	    return method_exists($this, $method);
	}

    /**
     * The hasProperty method, finds if the object contains a certain property.
     * @param String  $property
     * @access public
     * @return Boolean
     */
    public function hasProperty($property){
	    return property_exists($this, $property);
	}
	
	/**
     * The serialize method, serializes an object into string format.
	 * A serialized string can be stored in Constants, Database and Sessions.
     * @access public
     * @return String
     */
    public function serialize(){
        return serialize($this);
    }
   
    /**
     * The unserialize method, decode a string to its object representation.
	 * This method can be used to retrieve object info from Constants, Database and Sessions.
	 * @param String  $string
     * @access public
     * @return String
     */
    public function unserialize($string){
        return unserialize($string);
    }	
   
    /**
     * Magic method __toString() for Object class, returns object information.
     * @access public
     * @return String
     */
    public function __toString(){
        return get_class($this);
    }    
}
?>

Concrete Class: Boolean(just an example, the real subclasses are way too long for posting here)


<?php

namespace Resource\\Native;
use Exception;

/**
 * The Boolean Class, extending the root Object class.
 * This class serves as a wrapper class for primitive data type boolean.
 * It is a final class, no child class shall derive from Boolean.
 * @category Resource
 * @package Native
 * @author Hall of Famer 
 * @copyright Mysidia Adoptables Script
 * @link http://www.mysidiaadoptables.com
 * @since 1.3.2
 * @todo Not much at this point.
 * @final
 *
 */

final class Boolean extends Object{
  	
	/**
	 * Size constant, specifies the size a boolean value occupies.
    */
	const Size = 8;
	
	/**
	 * BooleanTrue constant, defines the True value for Boolean.
    */
    const BooleanTRUE = TRUE;
	
    /**
	 * BooleanFALSE constant, defines the False value for Boolean.
    */
    const BooleanFALSE = FALSE;
	
	/**
	 * The value property, which stores the primitive value for this Boolean object. 
	 * @access private
	 * @var Boolean
    */
    private $value;
      
    /**
     * Constructor of Boolean Class, initializes the Boolean wrapper class.
	 * If supplied argument is not of boolean type, type casting will be converted.
	 * @param Any  $param
     * @access public
     * @return Void
     */
    public function __construct($param){
	    if(!is_bool($param)) $param = (boolean)$param;
        $this->value = $param;
    }

	/**
     * The getValue method, returns the primitive boolean value.
     * @access public
     * @return Boolean
     */
	public function getValue(){
	    return $this->value;
	}
	
	/**
     * The compareTo method, compares a boolean object to another.
     * @param Objective  $target	 
     * @access public
     * @return Int
     */
    public function compareTo(Objective $target){
	    if(!($target instanceof Boolean)) throw new Exception("Supplied argument must be a boolean value!");
        return ($this->equals($target))?0:($this->value ? 1 : -1);
    }

	/**
     * Magic method to_String() for Boolean class, casts boolean value into string.
     * @access public
     * @return String
     */
    public function __toString(){
        return (string)$this->value;
    }
	
    /**
     * Magic method __invoke() for Boolean class, it returns the primitive data value for manipulation.
     * @access public
     * @return Number
     */
    public function __invoke(){
        return $this->value;  
    }
}
?>


<?php  
interface Objective{

    /**
     * The equals method, checks whether target object is equivalent to this one.
     * @param Objective  $object     
     * @access public
     * @return Boolean
     */
    public function equals(Objective $object);
    
    /**
     * The getClassName method, returns class name of an instance. 
     * The return value may differ depending on child classes. 
     * @access public
     * @return String
     */    
    public function getClassName();
    
    /**
     * Magic method __clone() for Object Class, returns a copy of Object with additional operations.
     * @access public
     * @return Object
     */
    public function __clone();
    
    /**
     * Magic method to_String() for Object class, returns object information.
     * @access public
     * @return String
     */    
    public function __toString(); 
}



abstract class Object implements Objective{

	/**
	 * Constructor of Object Class, which simply serves as a marker for child classes.
	 * @access public
	 * @return Void
	 */
	public function __construct(){

	}

	/**
	 * Destructor of Object Class, which simply serves as a marker for child classes.
	 * @access public
	 * @return Void
	 */
	public function __destruct(){

	}

	/**
	 * Magic method __clone() for Object Class, returns a copy of Object with additional operations.
	 * @access public
	 * @return Object
	 */
	public function __clone(){

	}

	/**
	 * The getClass method, returns class name of an instance.
	 * The return value may differ depending on child classes.
	 * @access public
	 * @return String
	 */
	public function getClass(){
		return get_class($this);
	}

	/**
	 * The getClassName method, returns class name of an instance.
	 * It is alias to getClass method, its existence is for backward compatibility.
	 * @access public
	 * @return String
	 */
	public function getClassName(){
		return $this->getClass();
	}

	/**
	 * The equals method, checks whether target object is equivalent to this one.
	 * @param Objective  $object
	 * @access public
	 * @return Boolean
	 */
	public function equals(Objective $object){
		return ($this == $object);
	}

	/**
	 * The hashCode method, returns the hash code for the very Object.
	 * @access public
	 * @return Int
	 */
	public function hashCode(){
		return hexdec(spl_object_hash($this));
	}

	/**
	 * The hasMethod method, examines if the object has a certain method.
	 * @param String  $method
	 * @access public
	 * @return Boolean
	 */
	public function hasMethod($method){
		return method_exists($this, $method);
	}

	/**
	 * The hasProperty method, finds if the object contains a certain property.
	 * @param String  $property
	 * @access public
	 * @return Boolean
	 */
	public function hasProperty($property){
		return property_exists($this, $property);
	}

	/**
	 * The serialize method, serializes an object into string format.
	 * A serialized string can be stored in Constants, Database and Sessions.
	 * @access public
	 * @return String
	 */
	public function serialize(){
		return serialize($this);
	}
	 
	/**
	 * The unserialize method, decode a string to its object representation.
	 * This method can be used to retrieve object info from Constants, Database and Sessions.
	 * @param String  $string
	 * @access public
	 * @return String
	 */
	public function unserialize($string){
		return unserialize($string);
	}
	 
	/**
	 * Magic method __toString() for Object class, returns object information.
	 * @access public
	 * @return String
	 */
	public function __toString(){
		return get_class($this);
	}
}


final class Boolean extends Object{

	/**
	 * Size constant, specifies the size a boolean value occupies.
	 */
	const Size = 8;

	/**
	 * BooleanTrue constant, defines the True value for Boolean.
	 */
	const BooleanTRUE = TRUE;

	/**
	 * BooleanFALSE constant, defines the False value for Boolean.
	 */
	const BooleanFALSE = FALSE;

	/**
	 * The value property, which stores the primitive value for this Boolean object.
	 * @access private
	 * @var Boolean
	 */
	private $value;

	/**
	 * Constructor of Boolean Class, initializes the Boolean wrapper class.
	 * If supplied argument is not of boolean type, type casting will be converted.
	 * @param Any  $param
	 * @access public
	 * @return Void
	 */
	public function __construct($param){
		if(!is_bool($param)) $param = (boolean)$param;
		$this->value = $param;
	}

	/**
	 * The getValue method, returns the primitive boolean value.
	 * @access public
	 * @return Boolean
	 */
	public function getValue(){
		return $this->value;
	}

	/**
	 * The compareTo method, compares a boolean object to another.
	 * @param Objective  $target
	 * @access public
	 * @return Int
	 */
	public function compareTo(Objective $target){
		if(!($target instanceof Boolean)) throw new Exception("Supplied argument must be a boolean value!");
		return ($this->equals($target))?0:($this->value ? 1 : -1);
	}

	/**
	 * Magic method to_String() for Boolean class, casts boolean value into string.
	 * @access public
	 * @return String
	 */
	public function __toString(){
		return (string)$this->value;
	}

	/**
	 * Magic method __invoke() for Boolean class, it returns the primitive data value for manipulation.
	 * @access public
	 * @return Number
	 */
	public function __invoke(){
		return $this->value;
	}
}



$bool = new Boolean(true);

$bool2 = clone $bool;

var_dump($bool2);

This is a slightly slimmed down version of what you posted. It works fine for me, can you run that script and see if you have a problem?

However, I will say this despite it being off topic: Trying to use scalars as objects in PHP is a very bad idea until the PHP developers give us a way to manage it better.

Yeah you are right, it is working. Guess it only happens to certain classes though, its getting more complex than I thought. Due to the complexity of the code that generates 500 Internal Server Error, tracking down this problem is quite difficult. sigh Thank you for being this patient with me.

And yeah, I agree that the way PHP is currently handing primitive/scalar types makes them really hard to work as objects. These are wrapper class/object used only in collections, since I’ve designed a PHP Collection Framework(PCF) myself a few months ago, and these collections only accept objects. For this reason, scalars must be wrapped/boxed before they can be sent to collection objects.