Skip to content

Add stdext module for swoole-cli and enhance PHP standard library #5842

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Aug 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
947a0f4
module stdext
matyhtf Jul 25, 2025
7d2d707
update
matyhtf Jul 28, 2025
1c388fc
code format
matyhtf Jul 28, 2025
6ebfd05
code format
matyhtf Jul 28, 2025
e73eaf5
typed array
matyhtf Jul 30, 2025
218d825
code format
matyhtf Jul 30, 2025
0a623c4
update
matyhtf Jul 30, 2025
fd34f9b
init values
matyhtf Jul 30, 2025
e8b758b
fix
matyhtf Jul 30, 2025
437b522
update
matyhtf Jul 30, 2025
3fa0f45
add marco (#5832)
NathanFreeman Jul 31, 2025
8c7d041
fix
matyhtf Jul 31, 2025
a6448a6
add tests --filter=[unit]
matyhtf Jul 31, 2025
0f5aaff
refactor typed array --filter=[unit]
matyhtf Jul 31, 2025
fb7cd75
Update typed array --filter=[unit]
matyhtf Jul 31, 2025
f1f44fb
Update typed array --filter=[unit]
matyhtf Jul 31, 2025
6422a25
Update typed array --filter=[unit]
matyhtf Jul 31, 2025
1555c62
optimize code --filter=[unit]
matyhtf Aug 1, 2025
4eb4071
Fix --filter=[unit]
matyhtf Aug 1, 2025
95c5483
Update --filter=[unit]
matyhtf Aug 1, 2025
f8b8e2a
Update --filter=[unit]
matyhtf Aug 4, 2025
b36d7d9
fix --filter=[unit]
matyhtf Aug 5, 2025
be8c71e
fix --filter=[unit]
matyhtf Aug 5, 2025
6bbbe48
fix --filter=[unit]
matyhtf Aug 5, 2025
ee8e469
[6.1] optimize feature (#5840)
NathanFreeman Aug 6, 2025
0b18c66
Merge branch 'master' into stdext
matyhtf Aug 6, 2025
0934bc2
Fix --filter=[unit]
matyhtf Aug 6, 2025
a641e7e
Fix --filter=[unit]
matyhtf Aug 6, 2025
100d967
Update --filter=[unit]
matyhtf Aug 7, 2025
0366a47
Fix arginfo --filter=[unit]
matyhtf Aug 7, 2025
0da8b04
optimize feature (#5841)
NathanFreeman Aug 11, 2025
ed77525
Optimize --filter=[unit]
matyhtf Aug 11, 2025
8d0385d
Update ext-src/swoole_stdext.cc
matyhtf Aug 11, 2025
6d7b509
Optimize code --filter=[unit]
matyhtf Aug 11, 2025
dbf648a
Update thirdparty/php/zend/zend_execute.c
matyhtf Aug 11, 2025
9022d82
Update ext-src/swoole_stdext.cc
matyhtf Aug 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ if (DEFINED verbose)
add_definitions(-DSW_VERBOSE)
endif()

set(php_dir "" CACHE STRING "Set the root directory of PHP")

if (DEFINED php_dir)
set(PHP_CONFIG "${php_dir}/bin/php-config")
else ()
Expand Down
9 changes: 9 additions & 0 deletions config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ PHP_ARG_ENABLE([swoole-thread],
[AS_HELP_STRING([--enable-swoole-thread],
[Enable swoole thread support])], [no], [no])

PHP_ARG_ENABLE([swoole-stdext],
[whether to enable swoole stdext support],
[AS_HELP_STRING([--enable-swoole-stdext],
[Enable swoole stdext support([Experimental] This module is only used for swoole-cli. If you are unsure which feature you need, keep it disabled)])], [no], [no])

PHP_ARG_ENABLE([swoole-coro-time],
[whether to enable coroutine execution time ],
[AS_HELP_STRING([--enable-swoole-coro-time],
Expand Down Expand Up @@ -965,6 +970,10 @@ EOF
AC_DEFINE(SW_THREAD, 1, [enable swoole thread support])
fi

if test "$PHP_SWOOLE_STDEXT" != "no"; then
AC_DEFINE(SW_STDEXT, 1, [enable swoole stdext support])
fi

if test "$PHP_SOCKETS" = "yes"; then
AC_MSG_CHECKING([for php_sockets.h])

Expand Down
76 changes: 76 additions & 0 deletions examples/stdext/array.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
$array = [1, 2, 3, 4, 5];

$arr = $array->slice(1, 2);
var_dump($arr);

$array1 = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5];
$array2 = [6, 7, 8, 9, 10, 11, 12];

var_dump($array2->count());

// var_dump($array2->all(function ($value) {
// return $value > 10;
// }));

$input_array = array("FirSt" => 1, "SecOnd" => 4);
print_r($input_array->changeKeyCase(CASE_UPPER));

$array4 = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = $array4->search('green');
var_dump($key);

echo "==================================[contains]===================================\n";
$os = array("Mac", "Windows", "Linux");
var_dump($os->contains("Windows"));
var_dump($os->contains("Unix"));

echo "==================================[isList]===================================\n";
var_dump($array1->isList());
var_dump($array2->isList());

var_dump($array1->keys());
var_dump($array2->values());

echo "==================================[join]===================================\n";
var_dump(['a', 'b', 'c']->join(','));

echo "==================================[method not exists]===================================\n";
try {
$array->notExists();
} catch (throwable $e) {
echo "Caught exception: ", $e->getMessage(), "\n";
}

function odd($var)
{
// returns whether the input integer is odd
return $var & 1;
}

function even($var)
{
// returns whether the input integer is even
return !($var & 1);
}

echo "Odd :\n";
print_r($array1->filter("odd"));

echo "Even:\n";
print_r($array2->filter("even"));


echo "==================================[array_map]===================================\n";

$a = [1, 2, 3, 4, 5];
$b = $a->map(function ($n) {
return ($n * $n * $n);
});
var_dump($b);

echo "==================================[array_key_exists]===================================\n";
$searchArray = ['first' => null, 'second' => 4];

var_dump(isset($searchArray['first']));
var_dump($searchArray->keyExists('first'));
7 changes: 7 additions & 0 deletions examples/stdext/foreach.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php
$arr = typed_array('<int>');

$arr[] = 1;
// $arr[0] += 10;
// assert($arr[0] == 11);
$arr[0] .= "hello world";
24 changes: 24 additions & 0 deletions examples/stdext/ref.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

$fruits = array("lemon", "orange", "banana", "apple");
echo "Before sorting:\n";
foreach ($fruits as $key => $val) {
echo "fruits[" . $key . "] = " . $val . "\n";
}

$b = &$fruits;
$b->sort(SORT_NATURAL | SORT_FLAG_CASE);

echo "After sorting:\n";
foreach ($fruits as $key => $val) {
echo "fruits[" . $key . "] = " . $val . "\n";
}

$stack = array("orange", "banana", "apple", "raspberry");

$ref = &$stack;
$fruit = $ref->shift();
var_dump($stack);

$ref->unshift("kiwi");
var_dump($stack);
36 changes: 36 additions & 0 deletions examples/stdext/string.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* This file is part of Swoole.
*
* @link https://www.swoole.com
* @contact [email protected]
* @license https://github.com/swoole/library/blob/master/LICENSE
*/

declare(strict_types=1);
$str = 'hello world';
var_dump($str->toUpper());

var_dump($str->split(' ')->search('world'));
var_dump($str->length());
var_dump('test'->length());

var_dump($str->indexOf('world'));
var_dump($str->substr(1, 4));

var_dump($str->startsWith('hello'));
var_dump($str->endsWith('world'));
var_dump($str->endsWith('.php'));

var_dump($str->md5(), $str->sha1(), $str->crc32());
var_dump($str->hash('sha256'));
echo "==============================hash=====================\n";
var_dump($str->md5() === $str->hash('md5'));

$str = 'first=value&arr[]=foo+bar&arr[]=baz';
$output = $str->parseStr();
echo $output['first']; // value
echo $output['arr'][0]; // foo bar
echo $output['arr'][1]; // baz

var_dump($str->urlEncode());
7 changes: 7 additions & 0 deletions examples/stdext/typed_array.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php
$list = typed_array('<int>');

$list[] = 123;
$list[] = 345;
$list[] = 'hello'; // 异常

6 changes: 6 additions & 0 deletions examples/stdext/typed_array_map.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?php
$list = typed_array('<string, int>');

$list["hello"] = 123;
$list[] = 345;
$list["hello"] = 'hello';
46 changes: 43 additions & 3 deletions ext-src/php_swoole.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ BEGIN_EXTERN_C()

#include "stubs/php_swoole_arginfo.h"
#include "stubs/php_swoole_ex_arginfo.h"
#ifdef SW_STDEXT
#include "stubs/php_swoole_stdext_arginfo.h"
#endif
END_EXTERN_C()

#include "swoole_mime_type.h"
Expand Down Expand Up @@ -102,6 +105,10 @@ static PHP_FUNCTION(swoole_internal_call_user_shutdown_begin);
static PHP_FUNCTION(swoole_implicit_fn);
SW_EXTERN_C_END

#ifdef SW_STDEXT
#include "php_swoole_stdext.h"
#endif

// clang-format off
const zend_function_entry swoole_functions[] = {
PHP_FE(swoole_version, arginfo_swoole_version)
Expand Down Expand Up @@ -148,6 +155,32 @@ const zend_function_entry swoole_functions[] = {
ZEND_FE(swoole_name_resolver_lookup, arginfo_swoole_name_resolver_lookup)
ZEND_FE(swoole_name_resolver_add, arginfo_swoole_name_resolver_add)
ZEND_FE(swoole_name_resolver_remove, arginfo_swoole_name_resolver_remove)
// for stdext
#ifdef SW_STDEXT
ZEND_FE(swoole_call_array_method, arginfo_swoole_call_array_method)
ZEND_FE(swoole_call_string_method, arginfo_swoole_call_string_method)
ZEND_FE(swoole_call_stream_method, arginfo_swoole_call_stream_method)
ZEND_FE(swoole_array_search, arginfo_swoole_array_search)
ZEND_FE(swoole_array_contains, arginfo_swoole_array_contains)
ZEND_FE(swoole_array_join, arginfo_swoole_array_join)
ZEND_FE(swoole_array_key_exists, arginfo_swoole_array_key_exists)
ZEND_FE(swoole_array_map, arginfo_swoole_array_map)
ZEND_FE(swoole_str_split, arginfo_swoole_str_split)
ZEND_FE(swoole_parse_str, arginfo_swoole_parse_str)
ZEND_FE(swoole_hash, arginfo_swoole_hash)
ZEND_FE(swoole_typed_array, arginfo_swoole_typed_array)
ZEND_FE(swoole_array_is_typed, arginfo_swoole_array_is_typed)
ZEND_FE(swoole_str_is_empty, arginfo_swoole_str_is_empty)
ZEND_FE(swoole_array_is_empty, arginfo_swoole_array_is_empty)
ZEND_FE(swoole_str_match, arginfo_swoole_str_match)
ZEND_FE(swoole_str_match_all, arginfo_swoole_str_match_all)
ZEND_FE(swoole_str_json_decode, arginfo_swoole_str_json_decode)
ZEND_FE(swoole_str_json_decode_to_object, arginfo_swoole_str_json_decode_to_object)
ZEND_FE(swoole_str_replace, arginfo_swoole_str_replace)
ZEND_FE(swoole_str_ireplace, arginfo_swoole_str_ireplace)
ZEND_FE(swoole_array_replace_str, arginfo_swoole_array_replace_str)
ZEND_FE(swoole_array_ireplace_str, arginfo_swoole_array_ireplace_str)
#endif
PHP_FE_END /* Must be the last line in swoole_functions[] */
};

Expand Down Expand Up @@ -430,7 +463,7 @@ SW_API bool php_swoole_unserialize(zend_string *data, zval *zv) {
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
if (!unserialized) {
swoole_warning("unserialize() failed, Error at offset " ZEND_LONG_FMT " of %zd bytes",
(zend_long)((char *) p - ZSTR_VAL(data)),
(zend_long) ((char *) p - ZSTR_VAL(data)),
l);
}
return unserialized;
Expand Down Expand Up @@ -807,6 +840,10 @@ PHP_MINIT_FUNCTION(swoole) {
CG(function_table), "swoole_coroutine_create", CG(function_table), "go", arginfo_swoole_coroutine_create);
SW_FUNCTION_ALIAS(
CG(function_table), "swoole_coroutine_defer", CG(function_table), "defer", arginfo_swoole_coroutine_defer);
#ifdef SW_STDEXT
SW_FUNCTION_ALIAS(
CG(function_table), "swoole_typed_array", CG(function_table), "typed_array", arginfo_swoole_typed_array);
#endif
}

swoole_init();
Expand Down Expand Up @@ -875,6 +912,9 @@ PHP_MINIT_FUNCTION(swoole) {
php_swoole_thread_map_minit(module_number);
php_swoole_thread_arraylist_minit(module_number);
#endif
#ifdef SW_STDEXT
php_swoole_stdext_minit(module_number);
#endif

SwooleG.fatal_error = fatal_error;
Socket::default_buffer_size = SWOOLE_G(socket_buffer_size);
Expand Down Expand Up @@ -1589,7 +1629,7 @@ static PHP_FUNCTION(swoole_substr_unserialize) {
if ((zend_long) buf_len <= offset) {
RETURN_FALSE;
}
if (length <= 0 || length > (zend_long)(buf_len - offset)) {
if (length <= 0 || length > (zend_long) (buf_len - offset)) {
length = buf_len - offset;
}
zend::unserialize(return_value, buf + offset, length, options ? Z_ARRVAL_P(options) : NULL);
Expand Down Expand Up @@ -1629,7 +1669,7 @@ static PHP_FUNCTION(swoole_substr_json_decode) {
php_error_docref(nullptr, E_WARNING, "Offset must be less than the length of the string");
RETURN_NULL();
}
if (length <= 0 || length > (zend_long)(str_len - offset)) {
if (length <= 0 || length > (zend_long) (str_len - offset)) {
length = str_len - offset;
}
/* For BC reasons, the bool $assoc overrides the long $options bit for PHP_JSON_OBJECT_AS_ARRAY */
Expand Down
Loading
Loading