3v4l.org

run code in 200+ php & hhvm versions
Bugs & Features
<?php /** * @package at.app * @version 0.3[20151212] * @author Adrian <adrian@enspi.red> * @copyright 2014 - 2015 * @license GNU GPL V2 <http://gnu.org/licenses/gpl-2.0.txt> */ declare( strict_types = 1 ); namespace at\simple\app; use at\simple\app\api\modelable as modelableAPI; /** * base implementation of modelableAPI. * * concrete classes may define getter methods for any string <offset>, * with the following signature: * get<offset>( void ) : mixed * * concrete classes may define setter methods for any string <offset>, * with the following signature: * set<offset>( mixed $value ) : void * * concrete classes may define unsetter methods for any string <offset>, * with the following signature: * unset<offset>( void ) : void * * concrete classes may define validator methods for any string <offset>, * with the following signature: * validate<offset>( mixed $value, bool $throw ) : bool * any <offset> with a validator method must either be a literal offset, * or have a corresponding set<offset> method (@see self::offsetSet()). * if the $throw argument is TRUE, and validation fails, * the validator method must throw a DomainException. */ abstract class DomainModel extends \SPLFixedArray implements modelableAPI { /** * @const array literal property name => default value map. * if no default is specified for a property, null will be used. */ const DATA = []; /** * @const array|null list of enumerable offsets. * if null, defaults to PROP. */ const ENUM = null; /** * @const array|null list of json-serializable offsets. * if null, defaults to ENUM. */ const JSON = null; /** * @const array list of identifiable literal properties. */ const KEYS = []; /** * @const array literal property name => index map. */ const PROP = []; /** * @const array literal property name => type (data type|classname) map. */ const TYPE = []; /** * @type array runtime list of enumerable properties. */ private $_enum = []; /** * @see <http://php.net/SPLFixedArray.fromArray> */ public static function fromArray( array $array ) { return static::from_array( $array ); } /** * @see modelableAPI::from_array() */ public static function from_array( array $data ) : modelableAPI { $dataObject = new static; foreach( $array as $prop => $value ) { $dataObject->offsetSet( $prop, $value ); } return $dataObject; } public function __construct() { parent::__construct( count( self::PROP ) ); foreach( static::DATA as $prop => $default ) { $this->offsetSet( $prop, $default ); } $this->_enum = static::ENUM ?? array_keys( static::PROP ); } /** * @see <http://php.net/Iterator.current> */ public function current() { return $this->offsetGet( current( $this->_enum ) ); } /** * @see modelableAPI::getDefaults() */ public function getDefaults() : array { return static::DATA; } /** * @see modelableAPI::getKeys() */ public function getKeys() : array { $keys = []; foreach( static::KEYS as $key ) { $keys[$key] = $this->offsetGet( $key ); } return $keys; } /** * @see modelableAPI::getProperties() */ public function getProperties() : array { return $this->_enum; } /** * @see modealableAPI::getTypes() */ public function getTypes() : array { return static::TYPE; } /** * @see <http://php.net/jsonSerializable.jsonSerialize> */ public function jsonSerialize() { $props = static::JSON ?? $this->_enum; $jsonable = []; foreach( $props as $prop ) { $jsonable[$prop] = $this->offsetGet( $prop ); } return $jsonable; } /** * @see <http://php.net/Iterator.key> */ public function key() { return current( $this->_enum ); } /** * @see <http://php.net/Iterator.next> */ public function next() { next( $this->_enum ); } /** * @see <http://php.net/ArrayAccess.offsetExists> */ public function offsetExists( $offset ) { return ( method_exists( [$this, "get{$offset}"] ) || method_exists( [$this, "set{$offset}"] ) || isset( self::PROP[$offset] ) ); } /** * @see <http://php.net/ArrayAccess.offsetGet> * * @throws UnderflowException if offset does not exist or is not readable */ public function offsetGet( $offset ) { if( ! is_string( $offset ) ) { $t = gettype( $offset ); $m = "\$offset must be a string, [{$t}] provided"; throw new \InvalidArgumentException( $m, E_USER_WARNING ); } if( method_exists( [$this, "get{$offset}"] ) ) { return $this->{"get{$offset}"}(); } if( isset( self::PROP[$offset] ) ) { return parent::offsetGet( self::PROP[$offset] ); } $m = "no readable property [{$offset}]"; throw new \UnderflowException( $m, E_USER_WARNING ); } /** * @see <http://php.net/ArrayAccess.offsetSet> * * @throws DomainException if validation fails * @throws OverflowException if offset does not exist or is not settable */ public function offsetSet( $offset, $value ) { $this->offsetValid( $offset, $value, true ); if( method_exists( [$this, "set{$offset}"] ) ) { return $this->{"set{$offset}"}( $value ); } if( isset( self::PROP[$offset] ) ) { return parent::offsetSet( self::PROP[$offset], $value ); } $m = "no setable property [{$offset}]"; throw new \OverflowException( $m, E_USER_WARNING ); } /** * @see <http://php.net/ArrayAccess.offsetUnset> * * @throws UnderflowException if offset does not exist or is not unsettable */ public function offsetUnset( $offset ) { if( ! is_string( $offset ) ) { $t = gettype( $offset ); $m = "\$offset must be a string, [{$t}] provided"; throw new \InvalidArgumentException( $m, E_USER_WARNING ); } if( method_exists( [$this, "unset{$offset}"] ) ) { $this->{"unset{$offset}"}( $value ); } // props with non-null default values are required (cannot be unset) if( isset( static::PROP[$offset] ) && ! isset( static::DATA[$offset] ) ) { parent::offsetUnset( self::PROP[$offset], $value ); } $m = "no unsetable property [{$offset}]"; throw new \UnderflowException( $m, E_USER_WARNING ); } /** * @see modelableAPI::offsetValid() */ public function offsetValid( string $offset, $value, bool $throw=false ) : bool { if( ! $this->offsetExists( $offset ) ) { $m = "no offset [{$offset}] exists"; throw new \OverflowException( $m, E_USER_WARNING ); } if( (! isset( static::TYPE[$offset] )) || ($value instanceof static::TYPE[$offset] || gettype( $value ) === static::TYPE[$offset]) ) { if( (! method_exists( [$this, "validate{$offset}"] )) || $this->{"validate{$offset}"}( $value )) ) { return true; } } if( $throw ){ $m = "invalid value for property [{$offset}]"; throw new \DomainException( $m, E_USER_NOTICE ); } return false; } /** * @see <http://php.net/Iterator.rewind> */ public function rewind() { reset( $this->_enum ); } /** * @see <http://php.net/serializable.serialize> */ public function serialize() { return serialize( parent::toArray() ); } /** nope. */ public function setSize( $size ) {} /** * @see modelableAPI::toArray() */ public function toArray() : array { $enumerable = []; foreach( $this->_enum as $prop ) { $enumerable[$prop] = $this->offsetGet( $prop ); } return $enumerable; } /** * @see <http://php.net/serializable.unserialize> */ public function unserialize( $serialized ) { $props = unserialize( $serialized ); if( ! (is_array( $props ) && (count( $props ) === count( static::PROP ))) ) { $m = '$serialized is not valid property data'; throw new \InvalidArgumentException( $m, E_USER_ERROR ); } $this->__construct(); foreach( (array) unserialize( $serialized ) as $index => $value ) { $offset = array_search( $index, static::PROP ); $this->offsetSet( $offset, $value ); } } /** * @see <http://php.net/Iterator.valid> */ public function valid() { return $this->offsetExists( current( $this->_enum ) ); } }
based on GSpTI

Here you find the average performance (time & memory) of each version. A grayed out version indicates it didn't complete successfully (based on exit-code).
Note: hhvm uses a JIT which only kicks in after a few runs. Since we run scripts only once, hhvm always runs slower.

VersionSystem time (s)User time (s)Memory (MiB)
7.0.00.0100.07720.14
5.6.160.0030.04320.48
5.6.150.0130.07318.19
5.6.140.0030.08318.15
5.6.130.0100.07718.19
5.6.120.0130.07321.15
5.6.110.0070.03721.10
5.6.100.0100.07321.14
5.6.90.0070.08721.11
5.6.80.0030.08720.37
5.5.300.0100.08017.95
5.5.290.0070.06717.98
5.5.280.0030.07020.89
5.5.270.0070.08320.89
5.5.260.0070.03720.63
5.5.250.0170.07320.69
5.5.240.0100.07720.23
5.4.450.0230.05719.60
5.4.440.0200.05019.42
5.4.430.0200.05019.64
5.4.420.0200.05719.31
5.4.410.0270.05019.48
5.4.400.0270.04318.94
5.4.390.0230.05319.19
5.4.380.0200.05018.95
5.4.370.0630.05319.14
5.4.360.0200.05318.99
5.4.350.0170.05319.10
5.4.340.0330.04019.23
5.4.320.0200.05319.21
5.4.310.0130.05719.11
5.4.300.0170.05319.23
5.4.290.0130.05719.11
5.4.280.0230.05018.97
5.4.270.0200.06019.19
5.4.260.0300.04018.98
5.4.250.0170.05319.32
5.4.240.0200.05019.18
5.4.230.0300.04019.22
5.4.220.0170.05719.30
5.4.210.0200.05319.32
5.4.200.0170.05319.12
5.4.190.0170.05318.94
5.4.180.0170.05319.12
5.4.170.0230.04719.25
5.4.160.0300.05019.17
5.4.150.0130.05718.96
5.4.140.0130.05716.53
5.4.130.0200.04316.59
5.4.120.0200.04716.59
5.4.110.0170.05016.59
5.4.100.0230.04316.59
5.3.290.0230.04714.78
5.3.280.0230.04714.48
5.3.270.0130.05714.74
5.3.260.0230.04714.68
5.3.250.0230.04714.65
5.3.240.0200.05014.58
5.3.230.0170.05314.82
5.3.220.0230.04314.62
5.3.210.0100.06014.62
5.3.200.0230.04314.55