<?php
/**
* JAVA Autoboxing (part of Lotos Framework)
*
* Copyright (c) 2005-2010 Artur Graniszewski (aargoth@boo.pl)
* All rights reserved.
*
* @category Library
* @package Lotos
* @subpackage DataTypes
* @copyright Copyright (c) 2005-2010 Artur Graniszewski (aargoth@boo.pl)
* @license GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007
* @version $Id$
*/
final class VariablesManager
{
/**
* Security checks
*
* @var bool
*/
private static $initFinished = false;
/**
* Minimal string size to cache.
*
* @var integer
*/
private static $minStringSize;
/**
* Number of the most current pointer.
*
* @var int
*/
private static $counter;
public static $memory = array();
/**
* Internal pool
* array($privateInternId =>
* array(
* [0] - Variable value
* [1] - Number of different instances sharing this variable
* [2] - Variable length
* [3] - Public Intern id
* )
* )
*/
private static $internPool = array();
/**
* Array of internal pools' names.
*
* @var string[]
*/
private static $internPoolId = array();
/**
* Number of the most current internal pool id.
*
* @var int
*/
private static $internPoolCounter = 1;
/**
* Initializes new variable of the given type and returns C-like pointer to it.
*
* It allows us to do variable type enforcing and silent object casting
*
* @param String Data type
* @return mixed Pointer to variable
* @todo change to array pool?
*/
public static function & getNewPointer($dataType) {
do {
++self::$counter;
$name = 'vm_var_'.self::$counter;
} while (isset(VariablesManager::$memory[$name]));
VariablesManager::$memory[$name] = $dataType;
if(is_object($dataType) && in_array('setPointer', get_class_methods($dataType))) {
$dataType->setPointer($name);
}
return VariablesManager::$memory[$name];
}
/**
* Returns intern reference of the existing string or creates and returns new one if it doesn't exist.
*
* @param string Simple type string
* @param string Internal pool id reserved for given string
* @param integer String length if calculated in a cache or null otherwise
* @return string String reference or null if string was invalid
*/
public static function & getIntern(& $string, & $internId, & $length = null) {
if(!$length) {
$length = strlen($string);
}
// cache only big strings
if($string === '' || !isset($string[self::$minStringSize]) || strlen($string) < self::$minStringSize) {
$internId = 0;
return $string;
}
$intern = & self::$internPool[$string];
if(isset($intern)) {
// variable exists in cache:
// increase the 'variable in use' counter by one
++$intern[1];
// set flags, etc
$length = $intern[2];
$internId = $intern[3];
return $intern[0];
} else {
$internId = self::$internPoolCounter++;
self::$internPool[$string] = array(0 => & $string, 1 => 1, 2 => & $length, 3 => $internId);
self::$internPoolId[$internId] = & $string;
return $string;
}
}
/**
* Unsets internal pool entity or decreases it's counter by one if variable is still in use by other instances.
*
* @param String intern
*/
public static function unsetIntern($internId) {
// is PHP shutting down? if it is, then avoid unnecesary cleaning, PHP will do it automatically
if($internId === 0) {
return;
}
$id = $internId;
$intern = & self::$internPool[self::$internPoolId[$internId]];
if(isset($intern)) {
--$intern[1];
if($intern[1] === 0) {
unset(self::$internPool[self::$internPoolId[$internId]]);
unset(self::$internPoolId[$internId]);
}
}
}
/**
* Initialises LOTOS Variables Manager.
* @access public
* @static
* @param integer Minimal variable size needed to put it in cache
* @return void
*/
public static function init(& $minStringSize = 2) {
self::$minStringSize = & $minStringSize;
if(self::$initFinished) {
return null;
}
self::$initFinished = true;
return new self();
}
/**
* LOTOS VM constructor.
*
* @return void
*/
private function __construct() {
}
/**
* LOTOS VM destructor (not used).
*
* @return void
*/
public function __destruct() {
}
/**
* Returns LOTOS VM statistics.
*
* @return mixed[] Array containing VM statistics.
*/
public function getPoolUsage() {
$len = 0; $shared = 0; $real = 0; $count = 0;
foreach(self::$internPool as $var) {
$len = strlen($var[0]);
$real += $len;
$shared += $len * $var[1];
$count += $var[1];
}
$segments = count(self::$internPool);
$ret = array('count' => $count, 'segments' => $segments, 'ratio' => ($segments > 0 ? ($count / $segments) * 100 : 0), 'memory' => array('real' => $real, 'shared' => $shared, 'ratio' => $real > 0 ? ($shared/$real) * 100 : 0));
return $ret;
}
}
/**
* AutoBoxedObject
*
* Every class needs to inherit this class in order to use PHP autoboxing.
* @author Artur Graniszewski
*/
abstract class AutoBoxedObject
{
/**
* C-like variable pointer.
*
* @var mixed
*/
protected $ref;
/**
* Internal ID used by caching mechanism (but not used frequently).
*
* @var int
*/
protected $internId;
/**
* Public constructor
*
* @return AutoBoxedObject
*/
public function __construct() {
}
/**
* Destructor used to datatype enforcing and final cleanups.
*
* @return void
*/
public function __destruct() {
if($this->ref === null) {
return;
}
if(VariablesManager::$memory[$this->ref] instanceof self) {
VariablesManager::$memory[$this->ref]->setPointer($this->ref);
} else if(is_scalar(VariablesManager::$memory[$this->ref])){
$val = VariablesManager::$memory[$this->ref];
$class = get_class($this);;
VariablesManager::$memory[$this->ref] = new $class($val);
VariablesManager::$memory[$this->ref]->setPointer($this->ref);
}
}
/**
* Sets C-like pointer for this object.
*
* @param mixed $name
*/
public function setPointer($name) {
$this->ref = $name;
}
/**
* Returns internal ID of this object.
*
* @return mixed
*/
public function getIntern() {
return $this->internId;
}
/**
* Returns string representation of this object.
*
* @return string
*/
public function toString() {
return $this->__toString();
}
}
class PrimitiveTypeWrapper extends AutoBoxedObject
{
protected $value = null;
protected $allowedCasting = array();
public function __toString() {
// NOTE: this must be a string, PHP forbids returning different type of variables in __toString() methods.
return "{$this->value}";
}
/**
* Converts this variable to Integer object.
*
* @return Integer
*/
public function & toInt() {
$x = & integer((int)$this->value);
return $x;
}
/**
* Converts this variable to Float object.
*
* @return Float
*/
public function & toFloat() {
$x = & float((int)$this->value);
return $x;
}
/**
* Converts this variable to String object.
*
* @return String
*/
public function & toString() {
$x = & string((string)$this->value);
return $x;
}
/**
* Destructor used to datatype enforcing and final cleanups.
*
* This time we are overwritting default Lotos VariablesManager behaviour and use
* strong data type enforcing
*
* @return void
*/
public function __destruct() {
if($this->ref === null) {
return;
}
if(is_object(VariablesManager::$memory[$this->ref]) && get_class(VariablesManager::$memory[$this->ref]) === get_class($this) && in_array('setPointer', get_class_methods(VariablesManager::$memory[$this->ref]))) {
VariablesManager::$memory[$this->ref]->setPointer($this->ref);
} else if(is_scalar(VariablesManager::$memory[$this->ref])){
$val = VariablesManager::$memory[$this->ref];
$class = get_class($this);
VariablesManager::$memory[$this->ref] = new $class($val);
VariablesManager::$memory[$this->ref]->setPointer($this->ref);
} else if(is_object(VariablesManager::$memory[$this->ref])) {
foreach($this->allowedCasting as $dataType) {
if(is_a(VariablesManager::$memory[$this->ref], $dataType)) {
return;
}
}
throw new Exception('Cannot cast '.get_class(VariablesManager::$memory[$this->ref]).' data type to '.get_class($this).'!');
}
}
}
/**
* Example class.
*
* Note: in order to use AutoBoxing, your class need to extend "AutoBoxedObject" class.
*/
class String extends PrimitiveTypeWrapper
{
protected $allowedCasting = array('Integer', 'Double', 'Float', 'Bool', 'Number');
public function __construct($value) {
// TYPE ENFORCING
if($value && !is_scalar ($value)) {
throw new Exception('The new value is not a scalar!!!');
}
$this->value = (string)$value;
}
public function getHex() {
$x = strtoupper(dechex($this->value));
$y = ceil(strlen($x) / 2);
return str_pad($x, $y * 2, '0', STR_PAD_LEFT);
}
}
/**
* Example class.
*
* Note: in order to use AutoBoxing, your class need to extend "AutoBoxedObject" class.
*/
class Bool extends PrimitiveTypeWrapper
{
public function __construct($value) {
// TYPE ENFORCING
if($value && !is_bool ($value)) {
throw new Exception('The new value is not a boolean type!!!');
}
$this->value = (bool)$value;
}
/**
* Converts this variable to String object.
*
* @return String
*/
public function & toString() {
$x = & string($this->value === true ? 'true' : ($this->value === false ? 'false' : 'null'));
return $x;
}
}
/**
* Example class.
*
* Note: in order to use AutoBoxing, your class need to extend "AutoBoxedObject" class.
*/
class Integer extends PrimitiveTypeWrapper
{
public function __construct($value) {
// TYPE ENFORCING
if($value && !is_int ($value) && !is_float($value)) {
throw new Exception('The new value cannot be cast to integer!!!');
}
$this->value = (int)$value;
}
public function toHex($useX = false) {
$x = strtoupper(dechex($this->value));
$y = ceil(strlen($x) / 2);
return ($useX ? '0x': '').str_pad($x, $y * 2, '0', STR_PAD_LEFT);
}
}
/**
* Example class.
*
* Note: in order to use AutoBoxing, your class need to extend "AutoBoxedObject" class.
*/
class Number extends PrimitiveTypeWrapper
{
protected $allowedCasting = array('Integer', 'Double', 'Float');
public function __construct($value) {
// TYPE ENFORCING
if($value && !is_int ($value) && !is_float($value) && !is_double($value)) {
throw new Exception('The new value cannot be cast to integer!!!');
}
$this->value = (double)$value;
}
public function toHex($useX = false) {
$x = strtoupper(dechex($this->value));
$y = ceil(strlen($x) / 2);
return ($useX ? '0x': '').str_pad($x, $y * 2, '0', STR_PAD_LEFT);
}
}
/**
* Example class.
*
* Note: in order to use AutoBoxing, your class need to extend "AutoBoxedObject" class.
*/
class Float extends PrimitiveTypeWrapper
{
protected $allowedCasting = array('Double');
public function __construct($value) {
// TYPE ENFORCING
if($value && !is_int ($value) && !is_float($value)) {
throw new Exception('The new value cannot be cast to float!!!');
}
$this->value = (float)$value;
}
}
/**
* Example class.
*
* Note: in order to use AutoBoxing, your class need to extend "AutoBoxedObject" class.
*/
class Double extends Float
{
}
/**
* Initializes a newly created Float object.
* @return Float created String object
*/
function & float($value = null) {
$type = ucfirst(strtolower(__FUNCTION__));
$x = & VariablesManager::getNewPointer(new $type($value));
return $x;
}
/**
* Initializes a newly created Float object.
* @return Float created String object
*/
function & double($value = null) {
$type = ucfirst(strtolower(__FUNCTION__));
$x = & VariablesManager::getNewPointer(new $type($value));
return $x;
}
/**
* Initializes a newly created Integer object.
* @return Integer created String object
*/
function & integer($value = null) {
$type = ucfirst(strtolower(__FUNCTION__));
$x = & VariablesManager::getNewPointer(new $type($value));
return $x;
}
/**
* Initializes a newly created String object.
* @return String created String object
*/
function & string($value = null) {
$type = ucfirst(strtolower(__FUNCTION__));
$x = & VariablesManager::getNewPointer(new $type($value));
return $x;
}
/**
* Initializes a newly created Bool object.
* @return Bool created String object
*/
function & bool($value = null) {
$type = ucfirst(strtolower(__FUNCTION__));
$x = & VariablesManager::getNewPointer(new $type($value));
return $x;
}
/**
* Initializes a newly created Bool object.
* @return Bool created String object
*/
function & number($value = null) {
$type = ucfirst(strtolower(__FUNCTION__));
$x = & VariablesManager::getNewPointer(new $type($value));
return $x;
}
// Lotos VM auto init (taken from the Lotos frameworks' autostart and executed manually below)
VariablesManager::init();
// ---------------------------------------------------------------------------
// simple autoboxing checks
$x = & integer(12);
$x = "$x" + 1;
echo $x.' => '.$x->toHex(true)."<br />";
$x = & float(12.12);
$x = "$x" * 2;
echo $x.' => '.$x->toInt()."<br />";
// ---------------------------------------------------------------------------
// with strong data type enforcing set integer value of 12 to the boolean variable
$x = & bool();
$x = true;
try {
$x = 12;
} catch (Exception $e) {
echo "Exception catched: ".$e->getMessage().' (code: '.$e->getCode().')<br />';
}
// ---------------------------------------------------------------------------
// with strong data type enforcing we cannot cast String ($y) to Number($x):
$x = & number();
$x = 12.33;
$y = & string("ok");
try {
$x = $y;
} catch(Exception $e) {
echo "Exception catched: ".$e->getMessage().' (code: '.$e->getCode().')<br />';
}
// ---------------------------------------------------------------------------
// but we can cast Number to Double, Float, etc.
$x = & number();
$x = 12.33;
$y = & double(3.33);
$x = $y;
echo $x.' => '.$x->toString()."<br />";
13 => 0x0D<br />24.24 => 24<br />Exception catched: The new value is not a boolean type!!! (code: 0)<br />Exception catched: Cannot cast String data type to Number! (code: 0)<br />3.33 => 3.33<br />
Output for 5.3.0 - 5.3.3
Strict Standards: Declaration of PrimitiveTypeWrapper::toString() should be compatible with that of AutoBoxedObject::toString() in /in/mqtub on line 356
13 => 0x0D<br />24.24 => 24<br />Exception catched: The new value is not a boolean type!!! (code: 0)<br />Exception catched: Cannot cast String data type to Number! (code: 0)<br />3.33 => 3.33<br />
Output for 5.2.0 - 5.2.17
Strict Standards: Declaration of PrimitiveTypeWrapper::toString() should be compatible with that of AutoBoxedObject::toString() in /in/mqtub on line 356
13 => 0x0D<br />24.24 => 24<br />Exception catched: The new value is not a boolean type!!! (code: 0)<br />
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Exception catched: Cannot cast String data type to Number! (code: 0)<br />
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
3.33 => 3.33<br />
Output for 5.0.2 - 5.0.5, 5.1.0 - 5.1.6
Strict Standards: Declaration of PrimitiveTypeWrapper::toString() should be compatible with that of AutoBoxedObject::toString() in /in/mqtub on line 356
Object id #2 => 0x01<br />Object id #3 => Object id #1<br />Exception catched: The new value is not a boolean type!!! (code: 0)<br />
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Exception catched: Cannot cast String data type to Number! (code: 0)<br />
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Object id #6 => Object id #4<br />
Output for 5.0.0 - 5.0.1
Strict Standards: Declaration of PrimitiveTypeWrapper::toString() should be compatible with that of AutoBoxedObject::toString() in /in/mqtub on line 356
Object id #2 => 0x01<br />Object id #3 => Object id #1<br />
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Strict Standards: is_a(): Deprecated. Please use the instanceof operator in /in/mqtub on line 348
Object id #6 => Object id #4<br />
Output for 4.4.2 - 4.4.9
Parse error: syntax error, unexpected T_CLASS in /in/mqtub on line 16
Process exited with code 255.