parent
0c77bc53e4
commit
6309346c9a
28 changed files with 2049 additions and 16 deletions
@ -0,0 +1,12 @@ |
||||
<?php |
||||
$array = [1, 3, 4]; |
||||
$array->push(5); |
||||
|
||||
$array->slice(1, 2)->find(3); |
||||
|
||||
$a = 100; |
||||
$a->add(99)->mul(2)->sub(100); |
||||
|
||||
$s = "hello"; |
||||
$s->upper(); |
||||
|
||||
@ -0,0 +1,5 @@ |
||||
<?php |
||||
$fp = fopen("php://stdin", "r"); |
||||
|
||||
$stream = |
||||
|
||||
@ -0,0 +1,7 @@ |
||||
<?php |
||||
use native_types; |
||||
function main() |
||||
{ |
||||
$a = 100; |
||||
$a->unknownMethod(); |
||||
} |
||||
@ -0,0 +1,7 @@ |
||||
<?php |
||||
use native_types; |
||||
function main() |
||||
{ |
||||
$a = 100; |
||||
$a->add(); |
||||
} |
||||
@ -0,0 +1,6 @@ |
||||
<?php |
||||
use native_types; |
||||
function main() |
||||
{ |
||||
(100)->add(99); |
||||
} |
||||
@ -0,0 +1,6 @@ |
||||
<?php |
||||
function main() |
||||
{ |
||||
$a = 100; |
||||
$a->add(1); |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
<?php |
||||
|
||||
class UniversalMethodCallTest extends \BaseTest |
||||
{ |
||||
public function testUnknownMethodOnInt() |
||||
{ |
||||
$this->exec("Cannot call method `unknownMethod()` on variable of type php::Int", 'universal-method-int-undefined.php'); |
||||
} |
||||
|
||||
public function testAddWithWrongArgCount() |
||||
{ |
||||
$this->exec('Method `add()` expects exactly 1 argument(s), 0 given', 'universal-method-int-wrong-args.php'); |
||||
} |
||||
|
||||
public function testMutatingMethodOnNonVarExpr() |
||||
{ |
||||
$this->exec('Cannot call mutating method `push()` on a non-variable expression', 'universal-method-mutating-expr.php'); |
||||
} |
||||
} |
||||
@ -0,0 +1,418 @@ |
||||
<?php |
||||
|
||||
namespace PhpAot\Php; |
||||
|
||||
use PhpParser\Node; |
||||
use PhpParser\Node\Expr; |
||||
use PhpParser\NodeAbstract; |
||||
|
||||
trait UniversalMethodCall |
||||
{ |
||||
protected const array UNIVERSAL_METHODS = [ |
||||
self::TYPE_INT => [ |
||||
'add' => ['handler' => 'calc_op', 'op' => '+', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 1], |
||||
'sub' => ['handler' => 'calc_op', 'op' => '-', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 1], |
||||
'mul' => ['handler' => 'calc_op', 'op' => '*', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 1], |
||||
'div' => ['handler' => 'calc_op', 'op' => '/', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 1], |
||||
'mod' => ['handler' => 'calc_op', 'op' => '%', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 1], |
||||
'inc' => ['handler' => 'calc_inc', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'dec' => ['handler' => 'calc_dec', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'toFloat' => ['handler' => 'convert_fn', 'fn' => 'toFloat', 'return_type' => self::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], |
||||
'toString' => ['handler' => 'convert_fn', 'fn' => 'toString', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'toBool' => ['handler' => 'convert_fn', 'fn' => 'toBool', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
], |
||||
self::TYPE_FLOAT => [ |
||||
'add' => ['handler' => 'calc_op', 'op' => '+', 'return_type' => self::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], |
||||
'sub' => ['handler' => 'calc_op', 'op' => '-', 'return_type' => self::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], |
||||
'mul' => ['handler' => 'calc_op', 'op' => '*', 'return_type' => self::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], |
||||
'div' => ['handler' => 'calc_op', 'op' => '/', 'return_type' => self::TYPE_FLOAT, 'min_args' => 1, 'max_args' => 1], |
||||
'inc' => ['handler' => 'calc_inc', 'return_type' => self::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], |
||||
'dec' => ['handler' => 'calc_dec', 'return_type' => self::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], |
||||
'toInt' => ['handler' => 'convert_fn', 'fn' => 'toInt', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'toString' => ['handler' => 'convert_fn', 'fn' => 'toString', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'toBool' => ['handler' => 'convert_fn', 'fn' => 'toBool', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
], |
||||
self::TYPE_BOOL => [ |
||||
'toInt' => ['handler' => 'convert_fn', 'fn' => 'toInt', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'toString' => ['handler' => 'convert_fn', 'fn' => 'toString', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
], |
||||
self::TYPE_STR => [ |
||||
// --- stdext string_methods (all use PHP standard functions) --- |
||||
'length' => ['handler' => 'php_fn', 'fn' => 'strlen', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'isEmpty' => ['handler' => 'str_is_empty', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'lower' => ['handler' => 'php_fn', 'fn' => 'strtolower', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'upper' => ['handler' => 'php_fn', 'fn' => 'strtoupper', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'lowerFirst' => ['handler' => 'php_fn', 'fn' => 'lcfirst', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'upperFirst' => ['handler' => 'php_fn', 'fn' => 'ucfirst', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'upperWords' => ['handler' => 'php_fn', 'fn' => 'ucwords', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'addCSlashes' => ['handler' => 'php_fn', 'fn' => 'addcslashes', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 1], |
||||
'addSlashes' => ['handler' => 'php_fn', 'fn' => 'addslashes', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'chunkSplit' => ['handler' => 'php_fn', 'fn' => 'chunk_split', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 2], |
||||
'countChars' => ['handler' => 'php_fn', 'fn' => 'count_chars', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 1], |
||||
'htmlEntityDecode' => ['handler' => 'php_fn', 'fn' => 'html_entity_decode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 2], |
||||
'htmlEntityEncode' => ['handler' => 'php_fn', 'fn' => 'htmlentities', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 3], |
||||
'htmlSpecialCharsEncode' => ['handler' => 'php_fn', 'fn' => 'htmlspecialchars', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 3], |
||||
'htmlSpecialCharsDecode' => ['handler' => 'php_fn', 'fn' => 'htmlspecialchars_decode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'trim' => ['handler' => 'php_fn', 'fn' => 'trim', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 2], |
||||
'lTrim' => ['handler' => 'php_fn', 'fn' => 'ltrim', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'rTrim' => ['handler' => 'php_fn', 'fn' => 'rtrim', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'parseStr' => ['handler' => 'php_fn', 'fn' => 'swoole_parse_str', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], |
||||
'parseUrl' => ['handler' => 'php_fn', 'fn' => 'parse_url', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 1], |
||||
'contains' => ['handler' => 'php_fn', 'fn' => 'str_contains', 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], |
||||
'incr' => ['handler' => 'php_fn', 'fn' => 'str_increment', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'decr' => ['handler' => 'php_fn', 'fn' => 'str_decrement', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'pad' => ['handler' => 'php_fn', 'fn' => 'str_pad', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 3], |
||||
'repeat' => ['handler' => 'php_fn', 'fn' => 'str_repeat', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 1], |
||||
'replace' => ['handler' => 'php_fn', 'fn' => 'str_replace', 'receiver_pos' => 3, 'return_type' => self::TYPE_STR, 'min_args' => 2, 'max_args' => 3], |
||||
'iReplace' => ['handler' => 'php_fn', 'fn' => 'str_ireplace', 'receiver_pos' => 3, 'return_type' => self::TYPE_STR, 'min_args' => 2, 'max_args' => 3], |
||||
'shuffle' => ['handler' => 'php_fn', 'fn' => 'str_shuffle', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'split' => ['handler' => 'php_fn', 'fn' => 'explode', 'receiver_pos' => 2, 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], |
||||
'startsWith' => ['handler' => 'php_fn', 'fn' => 'str_starts_with', 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], |
||||
'endsWith' => ['handler' => 'php_fn', 'fn' => 'str_ends_with', 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], |
||||
'wordCount' => ['handler' => 'php_fn', 'fn' => 'str_word_count', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 2], |
||||
'iCompare' => ['handler' => 'php_fn', 'fn' => 'strcasecmp', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 1], |
||||
'compare' => ['handler' => 'php_fn', 'fn' => 'strcmp', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 1], |
||||
'find' => ['handler' => 'php_fn', 'fn' => 'strstr', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'iFind' => ['handler' => 'php_fn', 'fn' => 'stristr', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'stripTags' => ['handler' => 'php_fn', 'fn' => 'strip_tags', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 2], |
||||
'stripCSlashes' => ['handler' => 'php_fn', 'fn' => 'stripcslashes', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'stripSlashes' => ['handler' => 'php_fn', 'fn' => 'stripslashes', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'iIndexOf' => ['handler' => 'php_fn', 'fn' => 'stripos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'indexOf' => ['handler' => 'php_fn', 'fn' => 'strpos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'lastIndexOf' => ['handler' => 'php_fn', 'fn' => 'strrpos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'iLastIndexOf' => ['handler' => 'php_fn', 'fn' => 'strripos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'lastCharIndexOf' => ['handler' => 'php_fn', 'fn' => 'strrchr', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 1], |
||||
'substr' => ['handler' => 'php_fn', 'fn' => 'substr', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 2], |
||||
'substrCompare' => ['handler' => 'php_fn', 'fn' => 'substr_compare', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 4], |
||||
'substrCount' => ['handler' => 'php_fn', 'fn' => 'substr_count', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 3], |
||||
'substrReplace' => ['handler' => 'php_fn', 'fn' => 'substr_replace', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 3], |
||||
'reverse' => ['handler' => 'php_fn', 'fn' => 'strrev', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'md5' => ['handler' => 'php_fn', 'fn' => 'md5', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'sha1' => ['handler' => 'php_fn', 'fn' => 'sha1', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'crc32' => ['handler' => 'php_fn', 'fn' => 'crc32', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'hash' => ['handler' => 'php_fn', 'fn' => 'swoole_hash', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 2], |
||||
'hashCode' => ['handler' => 'php_fn', 'fn' => 'crc32', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'base64Decode' => ['handler' => 'php_fn', 'fn' => 'base64_decode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'base64Encode' => ['handler' => 'php_fn', 'fn' => 'base64_encode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'urlDecode' => ['handler' => 'php_fn', 'fn' => 'urldecode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'urlEncode' => ['handler' => 'php_fn', 'fn' => 'urlencode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'rawUrlEncode' => ['handler' => 'php_fn', 'fn' => 'rawurlencode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'rawUrlDecode' => ['handler' => 'php_fn', 'fn' => 'rawurldecode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'match' => ['handler' => 'php_fn', 'fn' => 'swoole_str_match', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'matchAll' => ['handler' => 'php_fn', 'fn' => 'swoole_str_match_all', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'isNumeric' => ['handler' => 'php_fn', 'fn' => 'is_numeric', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
// mbstring |
||||
'mbUpperFirst' => ['handler' => 'php_fn', 'fn' => 'mb_ucfirst', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'mbLowerFirst' => ['handler' => 'php_fn', 'fn' => 'mb_lcfirst', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'mbTrim' => ['handler' => 'php_fn', 'fn' => 'mb_trim', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'mbSubstrCount' => ['handler' => 'php_fn', 'fn' => 'mb_substr_count', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 2], |
||||
'mbSubstr' => ['handler' => 'php_fn', 'fn' => 'mb_substr', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbUpper' => ['handler' => 'php_fn', 'fn' => 'mb_strtoupper', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'mbLower' => ['handler' => 'php_fn', 'fn' => 'mb_strtolower', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'mbFind' => ['handler' => 'php_fn', 'fn' => 'mb_strstr', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strpos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbLastIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strrpos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbILastIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strripos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbLastCharIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_strrchr', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbILastCharIndex' => ['handler' => 'php_fn', 'fn' => 'mb_strrichr', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbLength' => ['handler' => 'php_fn', 'fn' => 'mb_strlen', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 1], |
||||
'mbIFind' => ['handler' => 'php_fn', 'fn' => 'mb_stristr', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbIIndexOf' => ['handler' => 'php_fn', 'fn' => 'mb_stripos', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbCut' => ['handler' => 'php_fn', 'fn' => 'mb_strcut', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 3], |
||||
'mbRTrim' => ['handler' => 'php_fn', 'fn' => 'mb_rtrim', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'mbLTrim' => ['handler' => 'php_fn', 'fn' => 'mb_ltrim', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
'mbDetectEncoding' => ['handler' => 'php_fn', 'fn' => 'mb_detect_encoding', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 2], |
||||
'mbConvertEncoding' => ['handler' => 'php_fn', 'fn' => 'mb_convert_encoding', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 2], |
||||
'mbConvertCase' => ['handler' => 'php_fn', 'fn' => 'mb_convert_case', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 2], |
||||
// serialize |
||||
'unserialize' => ['handler' => 'php_fn', 'fn' => 'unserialize', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'unmarshal' => ['handler' => 'php_fn', 'fn' => 'unserialize', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'jsonDecode' => ['handler' => 'php_fn', 'fn' => 'swoole_str_json_decode', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 2], |
||||
'jsonDecodeToObject' => ['handler' => 'php_fn', 'fn' => 'swoole_str_json_decode_to_object', 'return_type' => self::TYPE_OBJECT, 'min_args' => 0, 'max_args' => 2], |
||||
// phpx C++ methods (no PHP function equivalent) |
||||
'equals' => ['handler' => 'direct_method', 'method' => 'equals', 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], |
||||
'append' => ['handler' => 'direct_method_mutate', 'method' => 'append', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 1], |
||||
// conversions |
||||
'toInt' => ['handler' => 'convert_fn', 'fn' => 'toInt', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'toFloat' => ['handler' => 'convert_fn', 'fn' => 'toFloat', 'return_type' => self::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], |
||||
'toBool' => ['handler' => 'convert_fn', 'fn' => 'toBool', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'toString' => ['handler' => 'identity', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
], |
||||
self::TYPE_ARRAY => [ |
||||
// --- stdext array_methods (all use PHP standard functions) --- |
||||
'all' => ['handler' => 'php_fn', 'fn' => 'array_all', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], |
||||
'any' => ['handler' => 'php_fn', 'fn' => 'array_any', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], |
||||
'changeKeyCase' => ['handler' => 'php_fn', 'fn' => 'array_change_key_case', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 1], |
||||
'chunk' => ['handler' => 'php_fn', 'fn' => 'array_chunk', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], |
||||
'column' => ['handler' => 'php_fn', 'fn' => 'array_column', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], |
||||
'countValues' => ['handler' => 'php_fn', 'fn' => 'array_count_values', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], |
||||
'diff' => ['handler' => 'php_fn', 'fn' => 'array_diff', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'diffAssoc' => ['handler' => 'php_fn', 'fn' => 'array_diff_assoc', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'diffKey' => ['handler' => 'php_fn', 'fn' => 'array_diff_key', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'filter' => ['handler' => 'php_fn', 'fn' => 'array_filter', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 2], |
||||
'find' => ['handler' => 'php_fn', 'fn' => 'array_find', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 1], |
||||
'flip' => ['handler' => 'php_fn', 'fn' => 'array_flip', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], |
||||
'intersect' => ['handler' => 'php_fn', 'fn' => 'array_intersect', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'intersectAssoc' => ['handler' => 'php_fn', 'fn' => 'array_intersect_assoc', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'isList' => ['handler' => 'php_fn', 'fn' => 'array_is_list', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'keyExists' => ['handler' => 'php_fn', 'fn' => 'array_key_exists', 'receiver_pos' => 2, 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 1], |
||||
'keyFirst' => ['handler' => 'php_fn', 'fn' => 'array_key_first', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'keyLast' => ['handler' => 'php_fn', 'fn' => 'array_key_last', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'keys' => ['handler' => 'php_fn', 'fn' => 'array_keys', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 2], |
||||
'map' => ['handler' => 'php_fn', 'fn' => 'array_map', 'receiver_pos' => 2, 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'pad' => ['handler' => 'php_fn', 'fn' => 'array_pad', 'return_type' => self::TYPE_ARRAY, 'min_args' => 2, 'max_args' => 2], |
||||
'product' => ['handler' => 'php_fn', 'fn' => 'array_product', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'rand' => ['handler' => 'php_fn', 'fn' => 'array_rand', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 1], |
||||
'reduce' => ['handler' => 'php_fn', 'fn' => 'array_reduce', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'replace' => ['handler' => 'php_fn', 'fn' => 'array_replace', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'reverse' => ['handler' => 'php_fn', 'fn' => 'array_reverse', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 1], |
||||
'search' => ['handler' => 'php_fn', 'fn' => 'array_search', 'receiver_pos' => 2, 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 2], |
||||
'slice' => ['handler' => 'php_fn', 'fn' => 'array_slice', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 3], |
||||
'sum' => ['handler' => 'php_fn', 'fn' => 'array_sum', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'unique' => ['handler' => 'php_fn', 'fn' => 'array_unique', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 1], |
||||
'values' => ['handler' => 'php_fn', 'fn' => 'array_values', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], |
||||
'count' => ['handler' => 'php_fn', 'fn' => 'count', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'merge' => ['handler' => 'php_fn', 'fn' => 'array_merge', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => -1], |
||||
'contains' => ['handler' => 'php_fn', 'fn' => 'in_array', 'receiver_pos' => 2, 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], |
||||
'join' => ['handler' => 'php_fn', 'fn' => 'implode', 'receiver_pos' => 2, 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 1], |
||||
'isTyped' => ['handler' => 'php_fn', 'fn' => 'swoole_array_is_typed', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], |
||||
'isEmpty' => ['handler' => 'direct_method', 'method' => 'empty', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
// mutating via PHP reference functions |
||||
'sort' => ['handler' => 'php_fn_ref', 'fn' => 'sort', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], |
||||
'pop' => ['handler' => 'php_fn_ref', 'fn' => 'array_pop', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'push' => ['handler' => 'php_fn_ref', 'fn' => 'array_push', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => -1], |
||||
'shift' => ['handler' => 'php_fn_ref', 'fn' => 'array_shift', 'return_type' => self::TYPE_VAR, 'min_args' => 0, 'max_args' => 0], |
||||
'unshift' => ['handler' => 'php_fn_ref', 'fn' => 'array_unshift', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => -1], |
||||
'splice' => ['handler' => 'php_fn_ref', 'fn' => 'array_splice', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 3], |
||||
'walk' => ['handler' => 'php_fn_ref', 'fn' => 'array_walk', 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], |
||||
'replaceStr' => ['handler' => 'php_fn', 'fn' => 'swoole_array_replace_str', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], |
||||
'iReplaceStr' => ['handler' => 'php_fn', 'fn' => 'swoole_array_ireplace_str', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 2], |
||||
// serialize |
||||
'serialize' => ['handler' => 'php_fn', 'fn' => 'serialize', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'marshal' => ['handler' => 'php_fn', 'fn' => 'serialize', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'jsonEncode' => ['handler' => 'php_fn', 'fn' => 'json_encode', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 2], |
||||
// phpx C++ methods (no PHP function equivalent) |
||||
'set' => ['handler' => 'direct_method_mutate', 'method' => 'set', 'return_type' => self::TYPE_ARRAY, 'min_args' => 2, 'max_args' => 2], |
||||
'get' => ['handler' => 'direct_method', 'method' => 'get', 'return_type' => self::TYPE_VAR, 'min_args' => 1, 'max_args' => 1], |
||||
'del' => ['handler' => 'direct_method_mutate', 'method' => 'del', 'return_type' => self::TYPE_ARRAY, 'min_args' => 1, 'max_args' => 1], |
||||
'clean' => ['handler' => 'direct_method_mutate', 'method' => 'clean', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], |
||||
// conversions |
||||
'toInt' => ['handler' => 'convert_fn', 'fn' => 'toInt', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'toFloat' => ['handler' => 'convert_fn', 'fn' => 'toFloat', 'return_type' => self::TYPE_FLOAT, 'min_args' => 0, 'max_args' => 0], |
||||
'toBool' => ['handler' => 'convert_fn', 'fn' => 'toBool', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'toString' => ['handler' => 'convert_fn', 'fn' => 'toString', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
], |
||||
self::TYPE_STREAM => [ |
||||
// --- stdext stream_methods --- |
||||
'write' => ['handler' => 'php_fn', 'fn' => 'fwrite', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 2], |
||||
'read' => ['handler' => 'php_fn', 'fn' => 'fread', 'return_type' => self::TYPE_STR, 'min_args' => 1, 'max_args' => 1], |
||||
'close' => ['handler' => 'php_fn', 'fn' => 'fclose', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'dataSync' => ['handler' => 'php_fn', 'fn' => 'fdatasync', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'sync' => ['handler' => 'php_fn', 'fn' => 'fsync', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'truncate' => ['handler' => 'php_fn', 'fn' => 'ftruncate', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 1], |
||||
'stat' => ['handler' => 'php_fn', 'fn' => 'fstat', 'return_type' => self::TYPE_ARRAY, 'min_args' => 0, 'max_args' => 0], |
||||
'seek' => ['handler' => 'php_fn', 'fn' => 'fseek', 'return_type' => self::TYPE_INT, 'min_args' => 1, 'max_args' => 2], |
||||
'tell' => ['handler' => 'php_fn', 'fn' => 'ftell', 'return_type' => self::TYPE_INT, 'min_args' => 0, 'max_args' => 0], |
||||
'lock' => ['handler' => 'php_fn', 'fn' => 'flock', 'return_type' => self::TYPE_BOOL, 'min_args' => 1, 'max_args' => 2], |
||||
'eof' => ['handler' => 'php_fn', 'fn' => 'feof', 'return_type' => self::TYPE_BOOL, 'min_args' => 0, 'max_args' => 0], |
||||
'getChar' => ['handler' => 'php_fn', 'fn' => 'fgetc', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 0], |
||||
'getLine' => ['handler' => 'php_fn', 'fn' => 'fgets', 'return_type' => self::TYPE_STR, 'min_args' => 0, 'max_args' => 1], |
||||
], |
||||
]; |
||||
|
||||
private const array MUTATING_HANDLERS = ['direct_method_mutate', 'php_fn_ref']; |
||||
|
||||
private const array TYPE_SEARCH_ORDER = [self::TYPE_STR, self::TYPE_ARRAY, self::TYPE_INT, self::TYPE_FLOAT, self::TYPE_BOOL, self::TYPE_STREAM]; |
||||
|
||||
protected function detectUniversalMethodReturnType(string $type, string $method): ?string |
||||
{ |
||||
if ($type === self::TYPE_VAR) { |
||||
foreach (self::TYPE_SEARCH_ORDER as $searchType) { |
||||
$def = static::UNIVERSAL_METHODS[$searchType][$method] ?? null; |
||||
if ($def !== null) { |
||||
return $def['return_type']; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
return static::UNIVERSAL_METHODS[$type][$method]['return_type'] ?? null; |
||||
} |
||||
|
||||
/** |
||||
* Search all type tables for a method. Returns [type, def] or null. |
||||
*/ |
||||
protected function findUniversalMethodAnyType(string $type, string $method): ?array |
||||
{ |
||||
if ($type === self::TYPE_VAR) { |
||||
foreach (self::TYPE_SEARCH_ORDER as $searchType) { |
||||
$def = static::UNIVERSAL_METHODS[$searchType][$method] ?? null; |
||||
if ($def !== null) { |
||||
return $def; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
return static::UNIVERSAL_METHODS[$type][$method] ?? null; |
||||
} |
||||
|
||||
/** |
||||
* @param string $receiver C++ expression for the receiver |
||||
* @param bool $isVar Whether the receiver is a variable (allows mutating methods) |
||||
*/ |
||||
protected function parseUniversalMethodCall(Node\Expr\MethodCall $expr, string $receiver, string $method, array $def, bool $isVar = true): ?string |
||||
{ |
||||
$this->validateUniversalMethodArgs($expr, $method, $def, $isVar); |
||||
|
||||
return match ($def['handler']) { |
||||
'calc_op' => $this->genUniversalCalcOp($receiver, $def['op'], $expr->args), |
||||
'calc_inc' => '(' . $receiver . ' + 1)', |
||||
'calc_dec' => '(' . $receiver . ' - 1)', |
||||
'direct_method' => $this->genUniversalDirectMethod($receiver, $def['method'], $expr->args), |
||||
'direct_method_mutate' => $this->genUniversalMutatingMethod($receiver, $def['method'], $expr->args), |
||||
'convert_fn' => $this->genUniversalConvertFn($receiver, $def['fn'], $def['return_type']), |
||||
'str_is_empty' => '(' . $receiver . '.length() == 0)', |
||||
'identity' => $receiver, |
||||
'php_fn' => $this->genUniversalPhpFn($receiver, $def['fn'], $expr->args, $def['receiver_pos'] ?? 0), |
||||
'php_fn_ref' => $this->genUniversalPhpFnRef($receiver, $def['fn'], $expr->args, $def['return_type']), |
||||
default => null, |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Generate a stream method call with null guard. |
||||
* Stream resources are nullable — throws Error if the receiver is null. |
||||
*/ |
||||
protected function genStreamNullGuard(Node\Expr\MethodCall $expr, string $receiver, string $method, array $def): string |
||||
{ |
||||
$this->validateUniversalMethodArgs($expr, $method, $def, false); |
||||
|
||||
// Evaluate receiver into temp var to avoid double evaluation |
||||
$streamVar = $this->addTmpVar(self::TYPE_VAR); |
||||
$this->context->beforeStmtLines[] = $streamVar . ' = ' . $receiver . ';'; |
||||
|
||||
$methodCall = match ($def['handler']) { |
||||
'php_fn' => $this->genUniversalPhpFn($streamVar, $def['fn'], $expr->args, $def['receiver_pos'] ?? 0), |
||||
'direct_method' => $this->genUniversalDirectMethod($streamVar, $def['method'], $expr->args), |
||||
default => null, |
||||
}; |
||||
|
||||
$errorMsg = "Cannot call method '{$method}' on a closed or invalid stream resource"; |
||||
$lambda = "[&]() -> php::Variant {\n"; |
||||
$lambda .= "if (!{$streamVar}.isResource()) {\n"; |
||||
$lambda .= "throwError(\"{$errorMsg}\");\n"; |
||||
$lambda .= "return php::null;\n"; |
||||
$lambda .= "}\n"; |
||||
$lambda .= "return {$methodCall};\n"; |
||||
$lambda .= "}()"; |
||||
|
||||
$tmpVar = $this->addTmpVar(self::TYPE_VAR); |
||||
$this->context->beforeStmtLines[] = "{$tmpVar} = {$lambda};"; |
||||
return $tmpVar; |
||||
} |
||||
|
||||
/** |
||||
* Wrap a non-variable receiver expression in the appropriate type conversion |
||||
* so that direct C++ method calls (e.g. .get(), .set()) work on the correct type. |
||||
*/ |
||||
private function wrapUniversalReceiver(string $type, string $expr): string |
||||
{ |
||||
$convFns = [ |
||||
self::TYPE_ARRAY => 'toArray', |
||||
self::TYPE_STR => 'toString', |
||||
self::TYPE_INT => 'toInt', |
||||
self::TYPE_FLOAT => 'toFloat', |
||||
self::TYPE_BOOL => 'toBool', |
||||
]; |
||||
if (isset($convFns[$type])) { |
||||
return 'php::' . $convFns[$type] . '(' . $expr . ')'; |
||||
} |
||||
return $expr; |
||||
} |
||||
|
||||
private function validateUniversalMethodArgs(Node\Expr\MethodCall $expr, string $method, array $def, bool $isVar): void |
||||
{ |
||||
$argCount = count($expr->args); |
||||
$maxArgs = $def['max_args']; |
||||
if ($maxArgs === -1) { |
||||
$maxArgs = PHP_INT_MAX; |
||||
} |
||||
if ($argCount < $def['min_args'] || $argCount > $maxArgs) { |
||||
$expected = $def['min_args'] === $def['max_args'] ? "exactly {$def['min_args']}" : "{$def['min_args']} to {$def['max_args']}"; |
||||
$this->fatalError($expr, "Method `{$method}()` expects {$expected} argument(s), {$argCount} given"); |
||||
} |
||||
|
||||
if (!$isVar && in_array($def['handler'], self::MUTATING_HANDLERS, true)) { |
||||
$this->fatalError($expr, 'Cannot call mutating method `' . $method . '()` on a non-variable expression'); |
||||
} |
||||
} |
||||
|
||||
protected function genUniversalCalcOp(string $object, string $op, array $args): string |
||||
{ |
||||
$argExpr = $this->parseExpr($args[0]->value); |
||||
return '(' . $object . ' ' . $op . ' ' . $argExpr . ')'; |
||||
} |
||||
|
||||
protected function genUniversalDirectMethod(string $object, string $cppMethod, array $args): string |
||||
{ |
||||
if (empty($args)) { |
||||
return $object . '.' . $cppMethod . '()'; |
||||
} |
||||
$argExprs = []; |
||||
foreach ($args as $arg) { |
||||
$argExprs[] = $this->parseExpr($arg->value); |
||||
} |
||||
return $object . '.' . $cppMethod . '(' . implode(', ', $argExprs) . ')'; |
||||
} |
||||
|
||||
protected function genUniversalMutatingMethod(string $object, string $cppMethod, array $args): string |
||||
{ |
||||
$call = $this->genUniversalDirectMethod($object, $cppMethod, $args); |
||||
return '(' . $call . ', ' . $object . ')'; |
||||
} |
||||
|
||||
protected function genUniversalConvertFn(string $receiver, string $fn, string $type): string |
||||
{ |
||||
return 'php::' . $fn . '(' . $receiver . ')'; |
||||
} |
||||
|
||||
protected function genUniversalPhpFn(string $receiver, string $phpFunc, array $args, int $receiverPos = 0): string |
||||
{ |
||||
$argExprs = []; |
||||
$userArgs = []; |
||||
foreach ($args as $arg) { |
||||
$userArgs[] = $this->parseExpr($arg->value); |
||||
} |
||||
|
||||
if ($receiverPos === 0) { |
||||
$argExprs = [$receiver]; |
||||
foreach ($userArgs as $ua) { |
||||
$argExprs[] = $ua; |
||||
} |
||||
} else { |
||||
foreach ($userArgs as $i => $ua) { |
||||
if ($i === $receiverPos - 1) { |
||||
$argExprs[] = $receiver; |
||||
} |
||||
$argExprs[] = $ua; |
||||
} |
||||
if ($receiverPos > count($userArgs)) { |
||||
$argExprs[] = $receiver; |
||||
} |
||||
} |
||||
|
||||
return 'php::call(' . $this->getFuncPtr($phpFunc) . ', php::ArgList{' . implode(', ', $argExprs) . '})'; |
||||
} |
||||
|
||||
protected function genUniversalPhpFnRef(string $receiver, string $phpFunc, array $args, string $returnType): string |
||||
{ |
||||
$tmpRef = $this->addTmpVar(self::TYPE_REF); |
||||
$tmpVar = $this->addTmpVar(self::TYPE_VAR); |
||||
$argExprs = ['&' . $tmpRef]; |
||||
foreach ($args as $arg) { |
||||
$argExprs[] = $this->parseExpr($arg->value); |
||||
} |
||||
$this->context->beforeStmtLines[] = $tmpRef . ' = ' . $receiver . '.toReference();'; |
||||
$this->context->beforeStmtLines[] = $tmpVar . ' = php::call(' . $this->getFuncPtr($phpFunc) . ', php::ArgList{' . implode(', ', $argExprs) . '});'; |
||||
return $tmpVar; |
||||
} |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
--TEST-- |
||||
array_method: 0 |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
$array = []; |
||||
$array[0] = 1; |
||||
$array[1] = 2; |
||||
$array[2] = 3; |
||||
$array[3] = 999; |
||||
Assert::false($array->isEmpty()); |
||||
Assert::eq($array->count(), count($array)); |
||||
Assert::eq($array->slice(0, 2), [1, 2]); |
||||
Assert::true($array->contains(999)); |
||||
Assert::eq($array->search(999), 3); |
||||
|
||||
$array2 = []; |
||||
Assert::true($array2->isEmpty()); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,18 @@ |
||||
--TEST-- |
||||
array_method: 1 |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$array = ["lemon", "orange", "banana", "apple"]; |
||||
$sorted_array = array("apple", "banana", "lemon", "orange",); |
||||
$array->sort(SORT_NATURAL | SORT_FLAG_CASE); |
||||
Assert::same($array, $sorted_array); |
||||
echo "done\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
done |
||||
@ -0,0 +1,29 @@ |
||||
--TEST-- |
||||
Universal method: array_method/2 (shift/unshift on Ref) |
||||
--FILE-- |
||||
<?php |
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
$array = array("orange", "banana", "apple", "raspberry"); |
||||
|
||||
$stack = $array; |
||||
Assert::eq($stack->count(), 4); |
||||
$fruit = $stack->shift(); |
||||
Assert::eq($fruit, "orange"); |
||||
Assert::eq($stack->count(), 3); |
||||
Assert::eq($array->count(), 4); |
||||
|
||||
$stack->unshift("mango"); |
||||
Assert::eq($stack->count(), 4); |
||||
|
||||
$stack2 = array("orange", "banana", "apple", "raspberry"); |
||||
Assert::eq($stack2->count(), 4); |
||||
$stack2->shift(); |
||||
Assert::eq($stack2->count(), 3); |
||||
|
||||
echo "done\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
done |
||||
@ -0,0 +1,300 @@ |
||||
--TEST-- |
||||
Universal method call: Array type methods |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function _even_filter($v) { return $v % 2 == 0; } |
||||
|
||||
function main() |
||||
{ |
||||
// push / count / isEmpty |
||||
$arr = []; |
||||
var_dump($arr->isEmpty()); |
||||
$arr->push(10); |
||||
$arr->push(20); |
||||
$arr->push(30); |
||||
var_dump($arr->count()); |
||||
var_dump($arr->isEmpty()); |
||||
|
||||
// pop |
||||
$arr = []; |
||||
$arr->push(100); |
||||
$arr->push(200); |
||||
$arr->push(300); |
||||
var_dump($arr->pop()); |
||||
var_dump($arr->count()); |
||||
var_dump($arr->pop()); |
||||
var_dump($arr->pop()); |
||||
|
||||
// get / set / del / keyExists |
||||
$arr = []; |
||||
$arr->set("name", "John"); |
||||
$arr->set("age", 30); |
||||
var_dump($arr->get("name")); |
||||
var_dump($arr->get("age")); |
||||
var_dump($arr->keyExists("age")); |
||||
$arr->del("age"); |
||||
var_dump($arr->keyExists("age")); |
||||
var_dump($arr->keyExists("name")); |
||||
|
||||
// clean |
||||
$arr = []; |
||||
$arr->push(1); |
||||
$arr->push(2); |
||||
$arr->push(3); |
||||
$arr->clean(); |
||||
var_dump($arr->isEmpty()); |
||||
var_dump($arr->count()); |
||||
|
||||
// keyExists / contains |
||||
$arr = []; |
||||
$arr->push("apple"); |
||||
$arr->push("banana"); |
||||
$arr->push("cherry"); |
||||
var_dump($arr->keyExists(0)); |
||||
var_dump($arr->keyExists(5)); |
||||
var_dump($arr->contains("banana")); |
||||
var_dump($arr->contains("grape")); |
||||
|
||||
// search |
||||
$arr = []; |
||||
$arr->push("red"); |
||||
$arr->push("green"); |
||||
$arr->push("blue"); |
||||
$arr->push("green"); |
||||
var_dump($arr->search("green")); |
||||
var_dump($arr->search("yellow")); |
||||
|
||||
// isList |
||||
$arr = []; |
||||
$arr->push("a"); |
||||
$arr->push("b"); |
||||
$arr->push("c"); |
||||
var_dump($arr->isList()); |
||||
$hash = []; |
||||
$hash->set("k", "v"); |
||||
var_dump($hash->isList()); |
||||
|
||||
// keys / values |
||||
$arr = []; |
||||
$arr->set("x", 1); |
||||
$arr->set("y", 2); |
||||
$arr->set("z", 3); |
||||
$keys = $arr->keys(); |
||||
var_dump($keys->count()); |
||||
var_dump($keys->contains("x")); |
||||
var_dump($keys->contains("y")); |
||||
$vals = $arr->values(); |
||||
var_dump($vals->contains(1)); |
||||
var_dump($vals->contains(3)); |
||||
|
||||
// keyFirst / keyLast |
||||
var_dump($arr->keyFirst()); |
||||
var_dump($arr->keyLast()); |
||||
|
||||
// join |
||||
$arr = []; |
||||
$arr->push("one"); |
||||
$arr->push("two"); |
||||
$arr->push("three"); |
||||
var_dump($arr->join(", ")); |
||||
|
||||
// merge (mutating) |
||||
$arr1 = []; |
||||
$arr1->push("a"); |
||||
$arr1->push("b"); |
||||
$arr2 = []; |
||||
$arr2->push("c"); |
||||
$arr2->push("d"); |
||||
$arr1->merge($arr2); |
||||
var_dump($arr1->count()); |
||||
var_dump($arr1->get(2)); |
||||
|
||||
// slice |
||||
$arr = []; |
||||
$arr->push("a"); |
||||
$arr->push("b"); |
||||
$arr->push("c"); |
||||
$arr->push("d"); |
||||
$arr->push("e"); |
||||
$sliced = $arr->slice(1, 3); |
||||
var_dump($sliced->count()); |
||||
var_dump($sliced->get(0)); |
||||
$sliced2 = $arr->slice(-2); |
||||
var_dump($sliced2->count()); |
||||
var_dump($sliced2->get(0)); |
||||
|
||||
// sort (mutating) |
||||
$arr = []; |
||||
$arr->push(3); |
||||
$arr->push(1); |
||||
$arr->push(4); |
||||
$arr->push(1); |
||||
$arr->push(5); |
||||
$arr->sort(); |
||||
var_dump($arr->get(0)); |
||||
var_dump($arr->get(1)); |
||||
var_dump($arr->get(4)); |
||||
|
||||
// reverse |
||||
$arr = []; |
||||
$arr->push(1); |
||||
$arr->push(2); |
||||
$arr->push(3); |
||||
$reversed = $arr->reverse(); |
||||
var_dump($reversed->get(0)); |
||||
var_dump($reversed->get(2)); |
||||
|
||||
// unique |
||||
$arr = []; |
||||
$arr->push("a"); |
||||
$arr->push("b"); |
||||
$arr->push("a"); |
||||
$arr->push("c"); |
||||
$unique = $arr->unique(); |
||||
var_dump($unique->count()); |
||||
|
||||
// flip |
||||
$arr = []; |
||||
$arr->set("a", 1); |
||||
$arr->set("b", 2); |
||||
$flipped = $arr->flip(); |
||||
var_dump($flipped->keyExists(1)); |
||||
|
||||
// sum / product |
||||
$arr = []; |
||||
$arr->push(2); |
||||
$arr->push(4); |
||||
$arr->push(6); |
||||
var_dump($arr->sum()); |
||||
var_dump($arr->product()); |
||||
|
||||
// chunk |
||||
$arr = []; |
||||
$arr->push(1); |
||||
$arr->push(2); |
||||
$arr->push(3); |
||||
$arr->push(4); |
||||
$arr->push(5); |
||||
$chunks = $arr->chunk(2); |
||||
var_dump($chunks->count()); |
||||
|
||||
// diff |
||||
$a = []; |
||||
$a->push("green"); |
||||
$a->push("red"); |
||||
$a->push("blue"); |
||||
$b = []; |
||||
$b->push("green"); |
||||
$b->push("yellow"); |
||||
$diff = $a->diff($b); |
||||
var_dump($diff->count()); |
||||
var_dump($diff->contains("red")); |
||||
var_dump($diff->contains("blue")); |
||||
|
||||
// filter |
||||
$arr = []; |
||||
$arr->push(1); |
||||
$arr->push(2); |
||||
$arr->push(3); |
||||
$arr->push(4); |
||||
$evens = $arr->filter('_even_filter'); |
||||
var_dump($evens->count()); |
||||
var_dump($evens->get(1)); |
||||
|
||||
// values |
||||
$arr = []; |
||||
$arr->set("x", 10); |
||||
$arr->set("y", 20); |
||||
$vals2 = $arr->values(); |
||||
var_dump($vals2->count()); |
||||
var_dump($vals2->get(0)); |
||||
var_dump($vals2->get(1)); |
||||
|
||||
// replace |
||||
$base = []; |
||||
$base->push("orange"); |
||||
$base->push("banana"); |
||||
$base->push("apple"); |
||||
$repl = []; |
||||
$repl->push("pineapple"); |
||||
$result = $base->replace($repl); |
||||
var_dump($result->get(0)); |
||||
|
||||
// jsonEncode |
||||
$arr = []; |
||||
$arr->set("name", "test"); |
||||
$arr->set("value", 123); |
||||
var_dump($arr->jsonEncode()); |
||||
|
||||
// toInt / toFloat / toBool / toString |
||||
$arr = []; |
||||
$arr->push(1); |
||||
var_dump($arr->toInt()); |
||||
var_dump($arr->toFloat()); |
||||
var_dump($arr->toBool()); |
||||
|
||||
echo "done\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
bool(true) |
||||
int(3) |
||||
bool(false) |
||||
int(300) |
||||
int(2) |
||||
int(200) |
||||
int(100) |
||||
string(4) "John" |
||||
int(30) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(true) |
||||
int(0) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(false) |
||||
int(1) |
||||
bool(false) |
||||
bool(true) |
||||
bool(false) |
||||
int(3) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
string(1) "x" |
||||
string(1) "z" |
||||
string(15) "one, two, three" |
||||
int(4) |
||||
string(1) "c" |
||||
int(3) |
||||
string(1) "b" |
||||
int(1) |
||||
string(1) "d" |
||||
int(1) |
||||
int(1) |
||||
int(5) |
||||
int(3) |
||||
int(1) |
||||
int(3) |
||||
bool(true) |
||||
int(12) |
||||
int(48) |
||||
int(3) |
||||
int(2) |
||||
bool(true) |
||||
bool(true) |
||||
int(2) |
||||
int(2) |
||||
int(2) |
||||
int(10) |
||||
int(20) |
||||
string(9) "pineapple" |
||||
string(27) "{"name":"test","value":123}" |
||||
int(1) |
||||
float(1) |
||||
bool(true) |
||||
done |
||||
@ -0,0 +1,175 @@ |
||||
--TEST-- |
||||
array_method: all array methods test |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function _odd($var) |
||||
{ |
||||
return $var & 1; |
||||
} |
||||
|
||||
function _cube($n) |
||||
{ |
||||
return ($n * $n * $n); |
||||
} |
||||
|
||||
function _sum($carry, $item) |
||||
{ |
||||
$carry += $item; |
||||
return $carry; |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$array = array("FirSt" => 1, "SecOnd" => 4); |
||||
Assert::eq($array->changeKeyCase(CASE_UPPER), array_change_key_case($array, CASE_UPPER)); |
||||
|
||||
$array = array('a', 'b', 'c', 'd', 'e'); |
||||
Assert::eq($array->chunk(2), array_chunk($array, 2)); |
||||
|
||||
$records = [ |
||||
[ |
||||
'id' => 2135, |
||||
'first_name' => 'John', |
||||
'last_name' => 'Doe', |
||||
], |
||||
[ |
||||
'id' => 3245, |
||||
'first_name' => 'Sally', |
||||
'last_name' => 'Smith', |
||||
], |
||||
[ |
||||
'id' => 5342, |
||||
'first_name' => 'Jane', |
||||
'last_name' => 'Jones', |
||||
], |
||||
[ |
||||
'id' => 5623, |
||||
'first_name' => 'Peter', |
||||
'last_name' => 'Doe', |
||||
] |
||||
]; |
||||
Assert::eq($records->column('id'), array_column($records, 'id')); |
||||
|
||||
$array = array(1, "hello", 1, "world", "hello"); |
||||
Assert::eq($array->countValues(), array_count_values($array)); |
||||
|
||||
$array1 = array("a" => "green", "red", "blue", "red"); |
||||
$array2 = array("b" => "green", "yellow", "red"); |
||||
Assert::eq($array1->diff($array2), array_diff($array1, $array2)); |
||||
|
||||
$array1 = array("a" => "green", "b" => "brown", "c" => "blue", "red"); |
||||
$array2 = array("a" => "green", "yellow", "red"); |
||||
Assert::eq($array1->diffAssoc($array2), array_diff_assoc($array1, $array2)); |
||||
|
||||
$array1 = array('blue' => 1, 'red' => 2, 'green' => 3, 'purple' => 4); |
||||
$array2 = array('green' => 5, 'yellow' => 7, 'cyan' => 8); |
||||
Assert::eq($array1->diffKey($array2), array_diff_key($array1, $array2)); |
||||
|
||||
$array = [6, 7, 8, 9, 10, 11, 12]; |
||||
Assert::eq($array->filter('_odd'), array_filter($array, '_odd')); |
||||
|
||||
$input = array("oranges", "apples", "pears"); |
||||
Assert::eq($input->flip(), array_flip($input)); |
||||
|
||||
$array1 = array("a" => "green", "red", "blue"); |
||||
$array2 = array("b" => "green", "yellow", "red"); |
||||
Assert::eq($array1->intersect($array2), array_intersect($array1, $array2)); |
||||
Assert::eq($array1->intersectAssoc($array2), array_intersect_assoc($array1, $array2)); |
||||
|
||||
$array = ['apple', 2, 3]; |
||||
Assert::eq($array->isList(), array_is_list($array)); |
||||
|
||||
$array = ['first' => 1, 'second' => 4]; |
||||
Assert::eq($array->keyExists('first'), array_key_exists('first', $array)); |
||||
|
||||
$array = ['a' => 1, 'b' => 2, 'c' => 3]; |
||||
Assert::eq($array->keyFirst(), array_key_first($array)); |
||||
Assert::eq($array->keyLast(), array_key_last($array)); |
||||
Assert::eq($array->keys(), array_keys($array)); |
||||
Assert::eq($array->values(), array_values($array)); |
||||
|
||||
$a = [1, 2, 3, 4, 5]; |
||||
Assert::eq($a->map('_cube'), array_map('_cube', $a)); |
||||
|
||||
$array = array(12, 10, 9); |
||||
Assert::eq($array->pad(5, 0), array_pad($array, 5, 0)); |
||||
|
||||
$a = array(2, 4, 6, 8); |
||||
Assert::eq($a->product(), array_product($a)); |
||||
|
||||
$array = array("Neo", "Morpheus", "Trinity", "Cypher", "Tank"); |
||||
Assert::notEq($array->rand(2), array_rand($array, 2)); |
||||
|
||||
$array = array(1, 2, 3, 4, 5); |
||||
Assert::eq($array->reduce('_sum'), array_reduce($array, '_sum')); |
||||
|
||||
$base = array("orange", "banana", "apple", "raspberry"); |
||||
$replacements = array(0 => "pineapple", 4 => "cherry"); |
||||
$replacements2 = array(0 => "grape"); |
||||
Assert::eq($base->replace($replacements, $replacements2), array_replace($base, $replacements, $replacements2)); |
||||
|
||||
$array = array("php", 4.0, array("green", "red")); |
||||
$rev = $array->reverse(); |
||||
Assert::eq($rev->reverse(), array_reverse(array_reverse($array))); |
||||
|
||||
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red'); |
||||
Assert::eq($array->search('green'), array_search('green', $array)); |
||||
|
||||
$array = array("a", "b", "c", "d", "e"); |
||||
Assert::eq($array->slice(-2, 1), array_slice($array, -2, 1)); |
||||
|
||||
$a = array(2, 4, 6, 8); |
||||
Assert::eq($a->sum(), array_sum($a)); |
||||
|
||||
$array = ["a" => "green", "red", "b" => "green", "blue", "red"]; |
||||
Assert::eq($array->unique(), array_unique($array)); |
||||
Assert::eq($array->count(), count($array)); |
||||
|
||||
$array = array("Mac", "NT", "Irix", "Linux"); |
||||
Assert::eq($array->contains("Mac"), in_array("Mac", $array)); |
||||
Assert::eq($array->join(","), implode(",", $array)); |
||||
|
||||
$array = []; |
||||
Assert::true($array->isEmpty()); |
||||
|
||||
$fruits1 = array("lemon", "orange", "banana", "apple"); |
||||
$fruits2 = array("lemon", "orange", "banana", "apple"); |
||||
sort($fruits2); |
||||
Assert::eq($fruits1->sort(), $fruits2); |
||||
Assert::eq($fruits1, $fruits2); |
||||
|
||||
$stack = array("orange", "banana", "apple", "raspberry"); |
||||
Assert::eq($stack->pop(), 'raspberry'); |
||||
Assert::eq(array_pop($stack), 'apple'); |
||||
|
||||
$array = array("red","green"); |
||||
$array->push("blue"); |
||||
Assert::eq($array, ["red","green", "blue"]); |
||||
array_push($array, "yellow"); |
||||
Assert::eq($array, ["red","green", "blue", "yellow"]); |
||||
|
||||
$stack = array("orange", "banana", "apple", "raspberry"); |
||||
Assert::eq($stack->shift(), 'orange'); |
||||
Assert::eq(array_shift($stack), 'banana'); |
||||
|
||||
$queue = ["orange", "banana"]; |
||||
$queue->unshift("orange"); |
||||
Assert::eq($queue, ["orange", "orange", "banana"]); |
||||
array_unshift($queue, "orange"); |
||||
Assert::eq($queue, ["orange", "orange", "orange", "banana"]); |
||||
|
||||
$array1 = array("red", "green", "blue", "yellow"); |
||||
$array2 = array("red", "green", "blue", "yellow"); |
||||
Assert::eq($array1->splice(2), array_splice($array2, 2)); |
||||
Assert::eq($array1, $array2); |
||||
|
||||
$find = array("Hello","world"); |
||||
$replace = array("B"); |
||||
$arr = array("Hello","world","!"); |
||||
Assert::eq($arr->replaceStr($find, $replace), str_replace($find, $replace, $arr)); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,93 @@ |
||||
--TEST-- |
||||
Universal method call on native typed variables |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
function main() |
||||
{ |
||||
// Int methods |
||||
$a = 100; |
||||
$a->add(50); |
||||
var_dump($a); |
||||
|
||||
$a->sub(30); |
||||
var_dump($a); |
||||
|
||||
$a->mul(2); |
||||
var_dump($a); |
||||
|
||||
$a->div(4); |
||||
var_dump($a); |
||||
|
||||
$b = $a->add(10); |
||||
var_dump($b); |
||||
var_dump($a); |
||||
|
||||
// Int conversion |
||||
var_dump($a->toString()); |
||||
var_dump($a->toFloat()); |
||||
|
||||
// String methods |
||||
$s = "hello world"; |
||||
var_dump($s->length()); |
||||
var_dump($s->upper()); |
||||
var_dump($s->substr(0, 5)); |
||||
$words = $s->split(" "); |
||||
var_dump($words->count()); |
||||
|
||||
// Array methods |
||||
$arr = []; |
||||
$arr->push(100); |
||||
$arr->push(200); |
||||
$arr->push(300); |
||||
var_dump($arr->count()); |
||||
var_dump($arr->get(0)); |
||||
var_dump($arr->get(1)); |
||||
var_dump($arr->keyExists(0)); |
||||
var_dump($arr->isEmpty()); |
||||
var_dump($arr->isList()); |
||||
|
||||
// Array pop |
||||
$last = $arr->pop(); |
||||
var_dump($last); |
||||
var_dump($arr->count()); |
||||
|
||||
// Array clean |
||||
$arr->clean(); |
||||
var_dump($arr->isEmpty()); |
||||
|
||||
// Float methods |
||||
$f = 3.14; |
||||
$f->add(1.0); |
||||
var_dump($f); |
||||
var_dump($f->toInt()); |
||||
|
||||
echo "done\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(100) |
||||
int(100) |
||||
int(100) |
||||
int(100) |
||||
int(110) |
||||
int(100) |
||||
string(3) "100" |
||||
float(100) |
||||
int(11) |
||||
string(11) "HELLO WORLD" |
||||
string(5) "hello" |
||||
int(2) |
||||
int(3) |
||||
int(100) |
||||
int(200) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
int(300) |
||||
int(2) |
||||
bool(true) |
||||
float(3.14) |
||||
int(3) |
||||
done |
||||
@ -0,0 +1,35 @@ |
||||
--TEST-- |
||||
stream_method: 0 |
||||
--SKIPIF-- |
||||
--FILE-- |
||||
<?php |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$filepath = "/tmp/test.txt"; |
||||
$fp = fopen($filepath, "w+"); |
||||
$rdata = random_bytes(1024); |
||||
Assert::greaterThan($fp->write($rdata->base64Encode()), $rdata->length()); |
||||
$fp->seek(0); |
||||
Assert::eq($rdata, $fp->read(8192)->base64Decode()); |
||||
Assert::eq($fp->stat(), fstat($fp)); |
||||
Assert::true($fp->sync()); |
||||
Assert::true($fp->dataSync()); |
||||
$fp->seek(100); |
||||
Assert::true($fp->tell() == 100); |
||||
Assert::true($fp->lock(LOCK_SH) == true); |
||||
Assert::true($fp->lock(LOCK_UN) == true); |
||||
Assert::true($fp->eof() == feof($fp)); |
||||
|
||||
$fp->seek(0); |
||||
$char = $fp->getChar(); |
||||
$fp->seek(0); |
||||
Assert::eq($char, fgetc($fp)); |
||||
$fp->seek(0); |
||||
$line = $fp->getLine(); |
||||
$fp->seek(0); |
||||
Assert::eq($line, fgets($fp)); |
||||
Assert::true($fp->truncate(1000)); |
||||
|
||||
Assert::true($fp->close()); |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,60 @@ |
||||
--TEST-- |
||||
Universal method call on stream resources with null guard |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
// Test 1: fopen()->write() returns bytes written (php_fn: fwrite) |
||||
$tmpfile = tempnam(sys_get_temp_dir(), 'aot'); |
||||
var_dump(fopen($tmpfile, 'w')->write("hello") !== false); |
||||
|
||||
// Test 2: fopen()->read() returns content (php_fn: fread) |
||||
// (re-open for reading — new stream) |
||||
var_dump(fopen($tmpfile, 'r')->read(5)); |
||||
|
||||
// Test 3: fopen()->close() returns bool (php_fn: fclose) |
||||
var_dump(fopen($tmpfile, 'r')->close()); |
||||
|
||||
// Test 4: fopen()->eof() returns bool (php_fn: feof) |
||||
$f = fopen($tmpfile, 'w'); |
||||
$f->write("test"); |
||||
$f->close(); |
||||
var_dump(fopen($tmpfile, 'r')->eof()); |
||||
|
||||
// Test 5: fopen()->tell() returns position (php_fn: ftell) |
||||
$r = fopen($tmpfile, 'r'); |
||||
var_dump($r->tell() === 0); |
||||
$r->read(2); |
||||
var_dump($r->tell() === 2); |
||||
$r->close(); |
||||
|
||||
// Test 6: fopen()->getChar() returns single char (php_fn: fgetc) |
||||
$f2 = fopen($tmpfile, 'r'); |
||||
var_dump($f2->getChar()); |
||||
$f2->close(); |
||||
|
||||
// Test 7: Null guard — fopen() with invalid mode causes null, |
||||
// calling write() should throw Error |
||||
try { |
||||
@fopen($tmpfile, 'INVALID_MODE')->write('data'); |
||||
var_dump(false); // should not reach here |
||||
} catch (\Error $e) { |
||||
var_dump(str_contains($e->getMessage(), 'closed or invalid stream resource')); |
||||
} |
||||
|
||||
unlink($tmpfile); |
||||
echo "OK\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
bool(true) |
||||
string(5) "hello" |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(true) |
||||
string(1) "t" |
||||
bool(true) |
||||
OK |
||||
|
||||
@ -0,0 +1,22 @@ |
||||
--TEST-- |
||||
string_method: 0 |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$string = 'hello world, this is a test string'; |
||||
Assert::false($string->isEmpty()); |
||||
Assert::eq($string->length(), strlen($string)); |
||||
Assert::eq($string->substr(0, 5), 'hello'); |
||||
Assert::eq($string->contains('world'), true); |
||||
Assert::eq($string->indexOf('test'), strpos($string, 'test')); |
||||
Assert::eq($string->split(' '), explode(' ', $string)); |
||||
|
||||
$empty = ''; |
||||
Assert::true($empty->isEmpty()); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,18 @@ |
||||
--TEST-- |
||||
string_method: 1 |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$str = "first=value&arr[]=foo+bar&arr[]=baz"; |
||||
|
||||
$output = $str->parseStr(); |
||||
Assert::eq($output['first'], 'value'); |
||||
Assert::eq($output['arr'][0], 'foo bar'); |
||||
Assert::eq($output['arr'][1], 'baz'); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,17 @@ |
||||
--TEST-- |
||||
string_method: json |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$array = ['a' => random_bytes(128)->base64Encode(), 'b' => random_int(1, PHP_INT_MAX), 'c' => php_uname()]; |
||||
|
||||
$str = $array->jsonEncode(); |
||||
Assert::notEmpty($str); |
||||
Assert::eq($str->jsonDecode(), $array); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,20 @@ |
||||
--TEST-- |
||||
string_method: marshal |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$array = []; |
||||
$array->set('a', 'marshal_test_value'); |
||||
$array->set('b', 100); |
||||
$array->set('c', 'system_info'); |
||||
|
||||
$str = $array->marshal(); |
||||
Assert::notEmpty($str); |
||||
Assert::eq($str->unmarshal(), $array); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,25 @@ |
||||
--TEST-- |
||||
string_method: match |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$str = 'foobarbaz'; |
||||
$regex1 = '/(foo)(bar)(baz)/'; |
||||
$matches = $str->match($regex1, PREG_OFFSET_CAPTURE); |
||||
|
||||
preg_match($regex1, $str, $matches2, PREG_OFFSET_CAPTURE); |
||||
Assert::eq($matches, $matches2); |
||||
|
||||
$html = "<b>bold text</b><a href=howdy.html>click me</a>"; |
||||
$regex2 = "/(<([\w]+)[^>]*>)(.*?)(<\/\\2>)/"; |
||||
preg_match_all($regex2, $html, $matches2, PREG_SET_ORDER); |
||||
|
||||
$matches = $html->matchAll($regex2, PREG_SET_ORDER); |
||||
Assert::eq($matches, $matches2); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,66 @@ |
||||
--TEST-- |
||||
string_method: mbstring |
||||
--SKIPIF-- |
||||
<?php |
||||
if (!extension_loaded("mbstring")) exit("skip mbstring extension not loaded"); |
||||
?> |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$text = 'bbbb大声向宇宙呐喊bbbb'; |
||||
Assert::eq($text->mbUpperFirst(), mb_ucfirst($text)); |
||||
|
||||
$text = 'Bbbb大声向宇宙呐喊bbbb'; |
||||
Assert::eq($text->mbLowerFirst(), mb_lcfirst($text)); |
||||
|
||||
$text = "\t\t大声向宇宙呐喊 :) ... "; |
||||
Assert::eq($text->mbTrim(), mb_trim($text)); |
||||
Assert::eq($text->mbLTrim(), mb_ltrim($text)); |
||||
Assert::eq($text->mbRTrim(), mb_rtrim($text)); |
||||
|
||||
$text = '大声大声大声向宇宙呐喊'; |
||||
Assert::eq($text->mbSubstrCount('大声'), mb_substr_count($text, '大声')); |
||||
|
||||
$text = "大声大声大声向宇宙呐喊"; |
||||
Assert::eq($text->mbSubstr(0, -1), mb_substr($text, 0, -1)); |
||||
|
||||
$text = 'b大声大声大声向宇宙呐喊'; |
||||
Assert::eq($text->mbUpper(), mb_strtoupper($text)); |
||||
|
||||
$text = 'BBBBBB大声大声大声向宇宙呐喊'; |
||||
Assert::eq($text->mbLower(), mb_strtolower($text)); |
||||
|
||||
$email = 'name我哦知道@example.com'; |
||||
Assert::eq($email->mbFind('哦'), mb_strstr($email, '哦')); |
||||
Assert::eq($email->mbIFind('道'), mb_stristr($email, '道')); |
||||
|
||||
$mystring1 = '当地特产'; |
||||
$mystring2 = '现在只是谈谈'; |
||||
Assert::true($mystring1->mbIndexOf('地') === mb_strpos($mystring1, '地')); |
||||
Assert::true($mystring2->mbIIndexOf('A') === mb_stripos($mystring2, 'a')); |
||||
|
||||
$mystring = '啦啦啦啦啦啦啦'; |
||||
Assert::true($mystring->mbLastIndexOf('好') === false); |
||||
Assert::true(mb_strrpos($mystring, '好') === false); |
||||
Assert::eq($mystring->mbILastIndexOf('啦'), mb_strripos($mystring, '啦')); |
||||
Assert::eq($mystring->mbLastCharIndexOf('啦'), mb_strrchr($mystring, '啦')); |
||||
Assert::eq($mystring->mbILastCharIndex('啦'), mb_strrichr($mystring, '啦')); |
||||
|
||||
$text = '啦啦啦啦啦啦啦'; |
||||
Assert::eq($text->mbLength(), mb_strlen($text)); |
||||
Assert::eq($text->mbCut(0, 2), mb_strcut($text, 0, 2)); |
||||
Assert::eq($text->mbDetectEncoding(), mb_detect_encoding($text)); |
||||
Assert::eq($text->mbConvertEncoding('GBK'), mb_convert_encoding($text, 'GBK')); |
||||
|
||||
$text = 'bbbbba啦啦啦啦啦啦啦'; |
||||
Assert::eq( |
||||
$text->mbConvertCase(MB_CASE_UPPER)->mbConvertCase(MB_CASE_LOWER), |
||||
mb_convert_case(mb_convert_case($text, MB_CASE_UPPER), MB_CASE_LOWER) |
||||
); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,167 @@ |
||||
--TEST-- |
||||
string_method: all string methods test |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
require __DIR__ . '/../../../src/Assert.php'; |
||||
|
||||
$text = 'aaaaaa'; |
||||
Assert::eq($text->length(), strlen($text)); |
||||
|
||||
$text = ''; |
||||
Assert::eq($text->isEmpty(), true); |
||||
|
||||
$text = 'A'; |
||||
Assert::eq($text->lower(), strtolower($text)); |
||||
Assert::eq($text->lowerFirst(), lcfirst($text)); |
||||
|
||||
$text = 'b'; |
||||
Assert::eq($text->upper(), strtoupper($text)); |
||||
Assert::eq($text->upperFirst(), ucfirst($text)); |
||||
|
||||
$text = 'hello world!'; |
||||
Assert::eq($text->upperWords(), ucwords($text)); |
||||
|
||||
$text = "PHP isThirty\nYears Old!\tYay to the Elephant!\n"; |
||||
$characters = "\0..\37!@\177..\377"; |
||||
Assert::eq($text->addCSlashes($characters), addCSlashes($text, $characters)); |
||||
|
||||
$text = "O'Reilly?"; |
||||
Assert::eq($text->addSlashes(), addslashes($text)); |
||||
|
||||
$text = 'This is quite a long string, which will get broken up because the line is going to be too long after base64 encoding it.'; |
||||
$encoded = $text->base64Encode(); |
||||
Assert::eq($encoded->chunkSplit(), chunk_split(base64_encode($text))); |
||||
|
||||
$text = "Two Ts and one F."; |
||||
Assert::eq($text->countChars(1), count_chars($text, 1)); |
||||
|
||||
$text = "I'll \"walk\" the <b>dog</b> now"; |
||||
$encoded = $text->htmlEntityEncode(); |
||||
Assert::eq($encoded->htmlEntityDecode(), html_entity_decode(htmlentities($text))); |
||||
|
||||
$text = "<a href='test'>Test</a>"; |
||||
$encoded = $text->htmlSpecialCharsEncode(ENT_QUOTES); |
||||
Assert::eq($encoded->htmlSpecialCharsDecode(), htmlspecialchars_decode(htmlspecialchars($text, ENT_QUOTES))); |
||||
|
||||
$text = "\t\tThese are a few words :) ... "; |
||||
Assert::eq($text->trim(), trim($text)); |
||||
Assert::eq($text->lTrim(), ltrim($text)); |
||||
Assert::eq($text->rTrim(), rtrim($text)); |
||||
|
||||
$text = "first=value&arr[]=foo+bar&arr[]=baz"; |
||||
parse_str($text, $result); |
||||
Assert::eq($text->parseStr(), $result); |
||||
|
||||
$url = 'http://username:password@hostname:9090/path?arg=value#anchor'; |
||||
Assert::eq($url->parseUrl(), parse_url($url)); |
||||
|
||||
$text = 'The lazy fox jumped over the fence'; |
||||
Assert::eq($text->contains('lazy'), str_contains($text, 'lazy')); |
||||
|
||||
$text = 'ABC'; |
||||
Assert::eq($text->incr(), str_increment($text)); |
||||
Assert::eq($text->decr(), str_decrement($text)); |
||||
|
||||
$text = "<body text=%BODY%>"; |
||||
Assert::eq($text->replace("%BODY%", "black"), str_replace("%BODY%", "black", $text)); |
||||
Assert::eq($text->iReplace("%body%", "black"), str_ireplace("%body%", "black", $text)); |
||||
|
||||
$text = "Alien"; |
||||
Assert::eq($text->pad(10), str_pad($text, 10)); |
||||
|
||||
$text = "-="; |
||||
Assert::eq($text->repeat(10), str_repeat($text, 10)); |
||||
|
||||
$text = 'abcdef'; |
||||
Assert::notEq($text->shuffle(), str_shuffle($text)); |
||||
|
||||
$text = "piece1 piece2 piece3 piece4 piece5 piece6"; |
||||
Assert::eq($text->split(' '), explode(' ', $text)); |
||||
|
||||
$text = 'The lazy fox jumped over the fence'; |
||||
Assert::eq($text->startsWith('The'), str_starts_with($text, 'The')); |
||||
Assert::eq($text->endsWith('fence'), str_ends_with($text, 'fence')); |
||||
|
||||
$text = "Hello fri3nd, you're\n looking good today!"; |
||||
Assert::eq($text->wordCount(0), str_word_count($text, 0)); |
||||
Assert::eq($text->wordCount(1), str_word_count($text, 1)); |
||||
Assert::eq($text->wordCount(2), str_word_count($text, 2)); |
||||
|
||||
$var1 = "Hello"; |
||||
$var2 = "hello"; |
||||
Assert::eq($var1->iCompare($var2), strcasecmp($var1, $var2)); |
||||
Assert::eq($var1->compare($var2), strcmp($var1, $var2)); |
||||
|
||||
$email = 'name@example.com'; |
||||
Assert::eq($email->find('@'), strstr($email, '@')); |
||||
Assert::eq($email->iFind('N'), stristr($email, 'N')); |
||||
|
||||
$text = '<p>Test paragraph.</p><!-- Comment --> <a href="#fragment">Other text</a>'; |
||||
Assert::eq($text->stripTags(), strip_tags($text)); |
||||
|
||||
$text = 'I\'d have a coffee.\nNot a problem.'; |
||||
Assert::eq($text->stripCSlashes(), stripcslashes($text)); |
||||
|
||||
$str = "Is your name O\'reilly?"; |
||||
Assert::eq($str->stripSlashes(), stripslashes($str)); |
||||
|
||||
$mystring1 = 'xyz'; |
||||
$mystring2 = 'ABC'; |
||||
Assert::true($mystring1->iIndexOf('A') === stripos($mystring1, 'a')); |
||||
Assert::true($mystring2->iIndexOf('A') === stripos($mystring2, 'a')); |
||||
Assert::eq($mystring2->indexOf('a'), strpos($mystring2, 'a')); |
||||
|
||||
$mystring = 'Elephpant'; |
||||
Assert::true($mystring->lastIndexOf('b') === false); |
||||
Assert::true(strrpos($mystring, 'b') === false); |
||||
Assert::eq($mystring->iLastIndexOf('E'), strripos($mystring, 'E')); |
||||
Assert::eq($mystring->lastCharIndexOf('E'), strrchr($mystring, 'E')); |
||||
|
||||
$text = "abcdef"; |
||||
Assert::eq($text->substr(0, -1), substr($text, 0, -1)); |
||||
Assert::eq($text->substrCompare("bc", 1, 2), substr_compare($text, "bc", 1, 2)); |
||||
|
||||
$text = 'This is a test'; |
||||
Assert::eq($text->substrCount('is'), substr_count($text, 'is')); |
||||
|
||||
$var = 'ABCDEFGH:/MNRPQR/'; |
||||
Assert::eq($var->substrReplace('bob', 0), substr_replace($var, 'bob', 0)); |
||||
|
||||
$var = 'abcdefghijklmn'; |
||||
Assert::eq($var->reverse(), strrev($var)); |
||||
Assert::eq($var->md5(), md5($var)); |
||||
Assert::eq($var->sha1(), sha1($var)); |
||||
Assert::eq($var->crc32(), crc32($var)); |
||||
Assert::eq($var->hash('sha256'), hash('sha256', $var)); |
||||
|
||||
$str = 'This is an encoded string'; |
||||
$encoded = $str->base64Encode(); |
||||
Assert::eq($encoded->base64Decode(), base64_decode(base64_encode($str))); |
||||
|
||||
$text = 'Data123!@-_ +'; |
||||
$encoded = $text->urlEncode(); |
||||
Assert::eq($encoded->urlDecode(), urldecode(urlencode($text))); |
||||
|
||||
$text = 'foo @+%/'; |
||||
$encoded = $text->rawUrlEncode(); |
||||
Assert::eq($encoded->rawUrlDecode(), rawurldecode(rawurlencode($text))); |
||||
|
||||
$text = "PHP is the web scripting language of choice."; |
||||
$result1 = $text->match("/php/i"); |
||||
preg_match("/php/i", $text, $result2); |
||||
Assert::eq($result1, $result2); |
||||
|
||||
$pattern = "/\(? (\d{3})? \)? (?(1) [\-\s] ) \d{3}-\d{4}/x"; |
||||
$subject = "Call 555-1212 or 1-800-555-1212"; |
||||
$result1 = $subject->matchAll($pattern); |
||||
preg_match_all($pattern, $subject, $result2); |
||||
Assert::eq($result1, $result2); |
||||
|
||||
$text = '112'; |
||||
Assert::eq($text->isNumeric(), is_numeric($text)); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
@ -0,0 +1,191 @@ |
||||
--TEST-- |
||||
Universal method call: String type methods |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
// length / isEmpty |
||||
$s = "hello world"; |
||||
var_dump($s->length()); |
||||
var_dump($s->isEmpty()); |
||||
$empty = ""; |
||||
var_dump($empty->isEmpty()); |
||||
|
||||
// upper / lower |
||||
$s = "Hello World"; |
||||
var_dump($s->upper()); |
||||
var_dump($s->lower()); |
||||
|
||||
// lowerFirst / upperFirst |
||||
$s = "Hello World"; |
||||
var_dump($s->lowerFirst()); |
||||
var_dump($s->upperFirst()); |
||||
|
||||
// upperWords |
||||
$s = "hello world!"; |
||||
var_dump($s->upperWords()); |
||||
|
||||
// trim / lTrim / rTrim |
||||
$s = " hello world "; |
||||
var_dump($s->trim()); |
||||
var_dump($s->lTrim()); |
||||
var_dump($s->rTrim()); |
||||
|
||||
// startsWith / endsWith / contains |
||||
$s = "hello world"; |
||||
var_dump($s->startsWith("hello")); |
||||
var_dump($s->startsWith("world")); |
||||
var_dump($s->endsWith("world")); |
||||
var_dump($s->endsWith("hello")); |
||||
var_dump($s->contains("lo wo")); |
||||
var_dump($s->contains("xxx")); |
||||
|
||||
// indexOf / lastIndexOf |
||||
$s = "hello world"; |
||||
var_dump($s->indexOf("world")); |
||||
var_dump($s->indexOf("xxx")); |
||||
var_dump($s->lastIndexOf("o")); |
||||
|
||||
// iCompare / compare |
||||
$s = "abc"; |
||||
var_dump($s->compare("abc")); |
||||
var_dump($s->compare("abd")); |
||||
var_dump($s->iCompare("ABC")); |
||||
|
||||
// reverse / md5 / sha1 / crc32 |
||||
$s = "hello"; |
||||
var_dump($s->reverse()); |
||||
var_dump($s->md5()); |
||||
var_dump($s->sha1()); |
||||
var_dump($s->crc32()); |
||||
|
||||
// base64Encode / base64Decode |
||||
$s = "hello"; |
||||
$encoded = $s->base64Encode(); |
||||
var_dump($encoded); |
||||
var_dump($encoded->base64Decode()); |
||||
|
||||
// urlEncode / urlDecode |
||||
$s = "hello world"; |
||||
$encoded = $s->urlEncode(); |
||||
var_dump($encoded); |
||||
var_dump($encoded->urlDecode()); |
||||
|
||||
// equals |
||||
$s = "hello"; |
||||
var_dump($s->equals("hello")); |
||||
var_dump($s->equals("HELLO")); |
||||
var_dump($s->equals("HELLO", true)); |
||||
|
||||
// isNumeric |
||||
$n1 = "123"; |
||||
$n2 = "12.3"; |
||||
$n3 = "abc"; |
||||
var_dump($n1->isNumeric()); |
||||
var_dump($n2->isNumeric()); |
||||
var_dump($n3->isNumeric()); |
||||
|
||||
// append (mutating) |
||||
$s = "hello"; |
||||
$s->append(" world"); |
||||
var_dump($s); |
||||
|
||||
// substr |
||||
$s = "hello world"; |
||||
var_dump($s->substr(6)); |
||||
var_dump($s->substr(0, 5)); |
||||
var_dump($s->substr(-5)); |
||||
|
||||
// split |
||||
$s = "a,b,c,d"; |
||||
$parts = $s->split(","); |
||||
var_dump($parts->count()); |
||||
var_dump($parts->get(0)); |
||||
var_dump($parts->get(2)); |
||||
|
||||
// stripTags |
||||
$s = "<p>Hello <b>World</b></p>"; |
||||
var_dump($s->stripTags("")); |
||||
|
||||
// addSlashes |
||||
$s = "O'Reilly"; |
||||
var_dump($s->addSlashes()); |
||||
|
||||
// toString (identity) |
||||
$s = "hello"; |
||||
var_dump($s->toString()); |
||||
|
||||
// toInt / toFloat / toBool |
||||
$s = "123"; |
||||
var_dump($s->toInt()); |
||||
$s = "3.14"; |
||||
var_dump($s->toFloat()); |
||||
$s = "1"; |
||||
var_dump($s->toBool()); |
||||
|
||||
// substrCount |
||||
$s = "hello hello world"; |
||||
var_dump($s->substrCount("hello")); |
||||
|
||||
// wordCount |
||||
$s = "hello world test"; |
||||
var_dump($s->wordCount()); |
||||
|
||||
echo "done\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(11) |
||||
bool(false) |
||||
bool(true) |
||||
string(11) "HELLO WORLD" |
||||
string(11) "hello world" |
||||
string(11) "hello World" |
||||
string(11) "Hello World" |
||||
string(12) "Hello World!" |
||||
string(11) "hello world" |
||||
string(13) "hello world " |
||||
string(13) " hello world" |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(false) |
||||
int(6) |
||||
bool(false) |
||||
int(7) |
||||
int(0) |
||||
int(-1) |
||||
int(0) |
||||
string(5) "olleh" |
||||
string(32) "5d41402abc4b2a76b9719d911017c592" |
||||
string(40) "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d" |
||||
int(907060870) |
||||
string(8) "aGVsbG8=" |
||||
string(5) "hello" |
||||
string(11) "hello+world" |
||||
string(11) "hello world" |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(false) |
||||
string(11) "hello world" |
||||
string(5) "world" |
||||
string(5) "hello" |
||||
string(5) "world" |
||||
int(4) |
||||
string(1) "a" |
||||
string(1) "c" |
||||
string(11) "Hello World" |
||||
string(9) "O\'Reilly" |
||||
string(5) "hello" |
||||
int(123) |
||||
float(3.14) |
||||
bool(true) |
||||
int(2) |
||||
int(3) |
||||
done |
||||
@ -0,0 +1,66 @@ |
||||
<?php |
||||
use native_types; |
||||
|
||||
function main() { |
||||
|
||||
|
||||
|
||||
// Int methods |
||||
$a = 100; |
||||
$a->add(50); |
||||
var_dump($a); |
||||
|
||||
$a->sub(30); |
||||
var_dump($a); |
||||
|
||||
$a->mul(2); |
||||
var_dump($a); |
||||
|
||||
$a->div(4); |
||||
var_dump($a); |
||||
|
||||
$b = $a->add(10); |
||||
var_dump($b); |
||||
var_dump($a); // $a also mutated |
||||
|
||||
// Int conversion |
||||
var_dump($a->toString()); |
||||
var_dump($a->toFloat()); |
||||
|
||||
// String methods |
||||
$s = "hello world"; |
||||
var_dump($s->length()); |
||||
var_dump($s->upper()); |
||||
var_dump($s->substr(0, 5)); |
||||
var_dump($s->split(" ")->count()); |
||||
|
||||
// Array methods |
||||
$arr = []; |
||||
$arr->append(100); |
||||
$arr->append(200); |
||||
$arr->append(300); |
||||
var_dump($arr->count()); |
||||
var_dump($arr->get(0)); |
||||
var_dump($arr->get(1)); |
||||
var_dump($arr->exists(0)); |
||||
var_dump($arr->empty()); |
||||
var_dump($arr->isList()); |
||||
|
||||
// Array pop |
||||
$last = $arr->pop(); |
||||
var_dump($last); |
||||
var_dump($arr->count()); |
||||
|
||||
// Array clean |
||||
$arr->clean(); |
||||
var_dump($arr->empty()); |
||||
|
||||
// Float methods |
||||
$f = 3.14; |
||||
$f->add(1.0); |
||||
var_dump($f); |
||||
var_dump($f->toInt()); |
||||
|
||||
echo "done\n"; |
||||
|
||||
} |
||||
@ -0,0 +1,93 @@ |
||||
--TEST-- |
||||
Universal method call on native typed variables |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
function main() |
||||
{ |
||||
// Int methods |
||||
$a = 100; |
||||
$a->add(50); |
||||
var_dump($a); |
||||
|
||||
$a->sub(30); |
||||
var_dump($a); |
||||
|
||||
$a->mul(2); |
||||
var_dump($a); |
||||
|
||||
$a->div(4); |
||||
var_dump($a); |
||||
|
||||
$b = $a->add(10); |
||||
var_dump($b); |
||||
var_dump($a); |
||||
|
||||
// Int conversion |
||||
var_dump($a->toString()); |
||||
var_dump($a->toFloat()); |
||||
|
||||
// String methods |
||||
$s = "hello world"; |
||||
var_dump($s->length()); |
||||
var_dump($s->upper()); |
||||
var_dump($s->substr(0, 5)); |
||||
$words = $s->split(" "); |
||||
var_dump($words->count()); |
||||
|
||||
// Array methods |
||||
$arr = []; |
||||
$arr->push(100); |
||||
$arr->push(200); |
||||
$arr->push(300); |
||||
var_dump($arr->count()); |
||||
var_dump($arr->get(0)); |
||||
var_dump($arr->get(1)); |
||||
var_dump($arr->keyExists(0)); |
||||
var_dump($arr->isEmpty()); |
||||
var_dump($arr->isList()); |
||||
|
||||
// Array pop |
||||
$last = $arr->pop(); |
||||
var_dump($last); |
||||
var_dump($arr->count()); |
||||
|
||||
// Array clean |
||||
$arr->clean(); |
||||
var_dump($arr->isEmpty()); |
||||
|
||||
// Float methods |
||||
$f = 3.14; |
||||
$f->add(1.0); |
||||
var_dump($f); |
||||
var_dump($f->toInt()); |
||||
|
||||
echo "done\n"; |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(100) |
||||
int(100) |
||||
int(100) |
||||
int(100) |
||||
int(110) |
||||
int(100) |
||||
string(3) "100" |
||||
float(100) |
||||
int(11) |
||||
string(11) "HELLO WORLD" |
||||
string(5) "hello" |
||||
int(2) |
||||
int(3) |
||||
int(100) |
||||
int(200) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
int(300) |
||||
int(2) |
||||
bool(true) |
||||
float(3.14) |
||||
int(3) |
||||
done |
||||
Loading…
Reference in new issue