static function encode( $data, $getterPrefixForObjectMethods = 'get', $ignoreNulls = false ) {
		$type = gettype( $data );
		$isObject = false;
		switch ( $type ) {		
			case 'string'	: return '"' . self::fixString( $data ) . '"';
			case 'number'	: ; // continue
			case 'integer'	: ; // continue
			case 'float'	: ; // continue			
			case 'double'	: return $data;				
			case 'boolean'	: return ( $data ) ? 'true' : 'false';
			case 'NULL'		: return 'null';
			case 'object'	: {
				$className = get_class( $data );
				if ( array_key_exists( $className, self::$conversions )
					&& is_callable( self::$conversions[ $className ] ) ) {
					$function = self::$conversions[ $className ];
					$convertedValue = call_user_func( $function, $data );
					return self::encode( $convertedValue );
				}
				$data = RTTI::getAttributes( $data, RTTI::anyVisibility(), $getterPrefixForObjectMethods );
				$isObject = true;
				// continue
			}
			case 'array'	: {
				$output = array();
				foreach ( $data as $key => $value ) {
					
					$encodedValue = self::encode( $value, $getterPrefixForObjectMethods );
					
					if ( $ignoreNulls && 'null' === $encodedValue ) { continue; }
					
					if ( is_numeric( $key ) ) {
						$output []= $encodedValue;
					} else {
						$encodedKey = self::encode( $key, $getterPrefixForObjectMethods );
						$output []= $encodedKey . ': ' . $encodedValue;
					}
				}
				return $isObject ? '{ ' . implode( ', ', $output ) . ' }' : '[ ' . implode( ', ', $output ) . ' ]';
			}
			default: return ''; // Not supported type
		}
	}