0

Taste Of JavaScript In Php Part-2 (Php 5.4+)

A few days ago I’ve posted an article, titled Taste Of JavaScript In Php (as my random ideas) where I wrote a class to create dynamic Php objects in the run time and it requires Php 5.4+ and this is another follow up of that article, the updated version of stdObject class, which requires Php 5.4+ and also supports some new features.

The old one is capable of creating dynamic objects at run time and also it can copy/clone other objects (typeof stdObjec) but this one is also capable of inherit other (typeof stdObject) objects and can change properties of the inherited object (by reference), it means, if any changes is made in the new object then the changes reflect on thr parent object too and also supports private properties but using a different approach. So here is the ugly code :

class Std {

	/**
	 * $prototype Main properties/methods
	 * holder, an  instanse of StdClass
	 * @var [stdClass]
	 */
	public $prototype = null;
	
	/**
	 * [$_name  Obejct's internal private property]
	 * @var [string]
	 */
	private $_name = null;
	
	/**
	 * Constructor, construct the Std object with array/Std object
	 * $clone false by default, it determines whether to extend or
	 * clone an object to create a new Std object, true for cloning
	 * 
	 * @param [string]  $instanceName [A name for the current instance]
	 * @param [mixed]   $array        [An array or Std object]
	 * @param boolean   $clone        [Default FALSE, TRUE if want to copy an existing instance]
	 */
	public function __construct($instanceName = null, $array = null, $clone = false)
	{
		//ini_set('display_errors', -1);
		set_exception_handler(array($this, '__exceptionHandler'));

		if(is_null($instanceName)){
			exit($instanceName);
		}

		$this->_name = $instanceName;
		$this->prototype = new \stdClass;

		if(!is_null($array) && is_array($array)){
			foreach ($array as $key => $value) {
				$this->prototype->$key = $value;
			}
		}
		elseif (is_object($array) && $array instanceof Std) {
			if(!$clone){
				$this->prototype = &$array->prototype;
			}
			else{
				$this->prototype = clone $array->prototype;
			}
		}
	}

	/**
	 * [__set Setter, Sets properties and methods]
	 * @param [string] $key   [Namne for the property]
	 * @param [mixed]  $value [Value for the property]
	 */
	public function __set($key, $value)
	{
		if(substr($key, 0, 1) == '_') {
			$this->$key = $value;
		}
		else {
			$this->prototype->$key = $value;
		}
	}

	/**
	 * __get Returns a property either from
	 * prototype property (stdobject) or from
	 * this when private properties, all private
	 * properties should have (_) as prefix
	 * 
	 * @param  @param [string] $key   [Namne for the property]
	 * @return [mixed]      
	 */
	public function __get($key)
	{
		if(isset($this->prototype->$key)){
			return $this->prototype->$key;
		}
		elseif(isset($this->{'_'. $key})) {
				return $this->{'_'. $key};
		}
		else{
        	throw new \Exception("Property :$key: doesn't exist", 1);
        }
    }

	/**
	 * [__call This method calls all methods]
	 * @param  [string] $method [Name of the method]
	 * @param  [array] $args    [Arguments for the method]
	 * @return [mixed]
	 */
	public function __call($method, $args)
	{
		if (isset($this->prototype->$method)) {
			$func = $this->prototype->$method->bindTo($this);
            return call_user_func_array($func, $args);
        }
        else{
        	throw new \Exception("Method :$method:() doesn't exist", 1);
        	
        }
	}


	/**
	 * Unset an item (property/method)
	 * from prototype, when unset called
	 * @param [string] $key [Key name to unset]
	 */
	public function __unset($key)
	{
		unset($this->prototype->$key);
	}

	/**
	 * [__exceptionHandler Custom Exception Handler for this class]
	 * @param  [object] $e [Exception object]
	 * @return [string]    [Prints the error and terminates the execution]
	 */
	public function __exceptionHandler($e)
	{
		$trace = $e->getTrace();
	    $result = ' Exception : ';
	    $result .=  preg_replace_callback("/:.*:/is", function($m) { return "" . str_replace(':', '', $m[0]) . ""; }, $e->getMessage());
	    $result .= ' in file "';
	    if($trace[0]['file'] != '') {
	      $result .= $trace[0]['file'];
	    }
	    $result .= '" at line : ' . $trace[0]['line'] . '';
	    echo $result;
	    exit;
	}

	/**
	 * getInstanceName Returns the name of the current
	 * that was given during the instance initialization
	 * @return [string] [Name of the current instance]
	 */
	public function getInstanceName()
	{
		return $this->_name;
	}

	/**
	 * [getInstanceLength Returns the total
	 * number of the members of the object
	 * @return [int] [count of properties/methods]
	 */
	public function getInstanceLength()
	{
		return count((Array)$this->prototype);
	}

	/**
	 * [__toString magic method]
	 * @return string [Name of thr current instance]
	 */
	public function  __toString()
	{
		return $this->_name;
	}
}
Basic Example/Usage :
$cls = new Std\Std;
$cls->runTest = function(){
  //...
};
//Call Method
$cls->runTest();
Create an instance with values in array :
$args = array(
  'property' => 'SomeText',
  'testMethod' => function(){
      return $this->property;
});
// Instantiate it with array filled with members
$anotherCls = new Std\Std($args);
echo $anotherCls->property; // SomeText
echo $anotherCls->testMethod(); // SomeText
// Add another method
$anotherCls->anotherTestMethod = function(){
    $this->property = 'New text';
    return $this->property;
};
// Changes happened
echo $anotherCls->property; // 'New text'
echo $anotherCls->anotherTestMethod(); // 'New text'
Create another object from an old object :

Create another object from $anotherCls and inherit (by reference) all it’s functionality.

$newRef = new Std\Std($anotherCls);
$newRef->properties = 'Some newtext'
// See changes in both objects
echo $newRef->testMethod(); // 'Some newtext'
echo $anotherCls->testMethod(); // 'Some newtext'
Copy/Clone a new one from old one (used Clone) :
$copiedobj = new Std($anotherCls. true);
$copiedobj->property = 'New value only for this';

// Changed in current instance
echo $copiedobj->property; // 'New value only for this'

// Not changed in current parent instance
echo $anotherCls->property; // 'Some newtext'
You may use pivate properies too :

It’s possible to use private properties using an underscore _ but you can retrieve it without the underscore (Sorry for this hack) :p

$clsNew->_privateProp = 'privateprop';
echo $clsNew->privateProp; // privateprop

Well, that’s it. This is just my random idea from my random (maybe good for nothing) thoughts and if you like it then it’s well but if you don’t like it then it’s also very well and if you have any feedback or can improve (if you are mad like me) it in any way then it’s really very very well.

→ The old version (another WTF) is here.

Latest Blog

0
Php

PHP – 8.0 Match Expression

In PHP 8.0 there is a new feature or I should say a new language construct (keyword) going to be introduced,  which has been implemented depending […]

0
Php

New Union Type in PHP – 8

A new RFC has been finished voting and accepted for PHP – 8. That is “Union Types”, which is an extension of PHP’s type system. […]