From: Dmitry Stogov Date: Thu, 17 Jul 2008 09:52:51 +0000 (+0000) Subject: support for closures X-Git-Tag: BEFORE_HEAD_NS_CHANGE~1226 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0cfa6a59778a53afb2138a86db8cd5fa0bc00900;p=php support for closures --- diff --git a/ext/curl/tests/curl_006.phpt b/ext/curl/tests/curl_006.phpt new file mode 100755 index 0000000000..2744fa27f9 --- /dev/null +++ b/ext/curl/tests/curl_006.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test curl_opt() function with CURLOPT_WRITEFUNCTION paremter set to a closure +--SKIPIF-- + +--FILE-- +); ***' . "\n"; + + $url = "{$host}/get.php?test=get"; + $ch = curl_init(); + + ob_start(); // start output buffering + curl_setopt($ch, CURLOPT_URL, $url); //set the url we want to use + curl_setopt($ch, CURLOPT_WRITEFUNCTION, function ($ch, $data) { + echo 'Data: '.$data; + return strlen ($data); + }); + + curl_exec($ch); + curl_close($ch); +?> +===DONE=== +--EXPECTF-- +*** Testing curl_setopt($ch, CURLOPT_WRITEFUNCTION, ); *** +Data: Hello World! +Hello World!===DONE=== diff --git a/ext/filter/tests/callback_closure.phpt b/ext/filter/tests/callback_closure.phpt new file mode 100755 index 0000000000..e27a31b37e --- /dev/null +++ b/ext/filter/tests/callback_closure.phpt @@ -0,0 +1,14 @@ +--TEST-- +callback function is a closure +--SKIPIF-- + +--FILE-- + $callback))); +?> +--EXPECT-- +string(4) "test" diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 8c8c3c32b5..1850facd4d 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -1457,7 +1457,7 @@ PHP_FUNCTION(mysqli_set_local_infile_handler) { MY_MYSQL *mysql; zval *mysql_link; - zval callback_name, *p_callback_name; + zval callback_name; zval *callback_func; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oz", &mysql_link, mysqli_link_class_entry, @@ -1467,7 +1467,7 @@ PHP_FUNCTION(mysqli_set_local_infile_handler) MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - if (UG(unicode)) { + if (UG(unicode) && Z_TYPE_P(callback_func) != IS_ARRAY && Z_TYPE_P(callback_func) != IS_OBJECT) { convert_to_string(callback_func); } @@ -1477,6 +1477,7 @@ PHP_FUNCTION(mysqli_set_local_infile_handler) zval_dtor(&callback_name); RETURN_FALSE; } + zval_dtor(&callback_name); /* save callback function */ if (!mysql->li_read) { @@ -1484,8 +1485,7 @@ PHP_FUNCTION(mysqli_set_local_infile_handler) } else { zval_dtor(mysql->li_read); } - p_callback_name = &callback_name; - ZVAL_ZVAL(mysql->li_read, p_callback_name, 0, 0); + ZVAL_ZVAL(mysql->li_read, callback_func, 1, 0); RETURN_TRUE; } diff --git a/ext/mysqli/tests/mysqli_set_local_infile_handler_closures.phpt b/ext/mysqli/tests/mysqli_set_local_infile_handler_closures.phpt new file mode 100755 index 0000000000..3bdf6bb78b --- /dev/null +++ b/ext/mysqli/tests/mysqli_set_local_infile_handler_closures.phpt @@ -0,0 +1,65 @@ +--TEST-- +mysqli_set_local_infile_handler() - use closures as handler +--SKIPIF-- + +--INI-- +mysqli.allow_local_infile=1 +--FILE-- + 10) + return 0; + + return strlen($buffer); + }; + + $file = create_standard_csv(1); + if (!try_handler(20, $link, $file, $callback_replace_buffer, null)) + printf("[008] Failure\n"); + + mysqli_close($link); + print "done!"; +?> +--EXPECTF-- +Callback set to 'Closure object' +Callback: 0 +Callback: 1 +done! \ No newline at end of file diff --git a/ext/pcntl/tests/signal_closure_handler.phpt b/ext/pcntl/tests/signal_closure_handler.phpt new file mode 100755 index 0000000000..ba9b8f5106 --- /dev/null +++ b/ext/pcntl/tests/signal_closure_handler.phpt @@ -0,0 +1,25 @@ +--TEST-- +Closures as a signal handler +--SKIPIF-- + +--FILE-- + +--EXPECT-- +Start! +Signal handler called! +Done! diff --git a/ext/session/tests/save_handler_closures.inc b/ext/session/tests/save_handler_closures.inc new file mode 100755 index 0000000000..50f33c1098 --- /dev/null +++ b/ext/session/tests/save_handler_closures.inc @@ -0,0 +1,9 @@ + diff --git a/ext/session/tests/session_set_save_handler_closures.phpt b/ext/session/tests/session_set_save_handler_closures.phpt new file mode 100755 index 0000000000..ac97ec9a11 --- /dev/null +++ b/ext/session/tests/session_set_save_handler_closures.phpt @@ -0,0 +1,99 @@ +--TEST-- +Test session_set_save_handler() function : using closures as callbacks +--INI-- +session.save_path= +session.name=PHPSESSID +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +*** Testing session_set_save_handler() : using closures as callbacks *** + +unicode(%d) "%s" + +Warning: session_module_name(): Cannot find named PHP session module () in %s on line %d +bool(false) + +Warning: session_module_name(): Cannot find named PHP session module (blah) in %s on line %d +bool(false) + +Warning: session_module_name(): Cannot find named PHP session module (foo) in %s on line %d +bool(false) +Open [%s,PHPSESSID] +Read [%s,%s] +array(3) { + [u"Blah"]=> + unicode(12) "Hello World!" + [u"Foo"]=> + bool(false) + [u"Guff"]=> + int(1234567890) +} +Write [%s,%s,Blah|U:12:"Hello World!";Foo|b:0;Guff|i:1234567890;] + +Notice: fwrite(): %d character unicode buffer downcoded for binary stream runtime_encoding in %s on line %d +Close [%s,PHPSESSID] +array(3) { + [u"Blah"]=> + unicode(12) "Hello World!" + [u"Foo"]=> + bool(false) + [u"Guff"]=> + int(1234567890) +} +Starting session again..! +Open [%s,PHPSESSID] +Read [%s,%s] +array(3) { + [u"Blah"]=> + unicode(12) "Hello World!" + [u"Foo"]=> + bool(false) + [u"Guff"]=> + int(1234567890) +} +Write [%s,%s,Blah|U:12:"Hello World!";Foo|b:0;Guff|i:1234567890;] + +Notice: fwrite(): %d character unicode buffer downcoded for binary stream runtime_encoding in %s on line %d +Close [%s,PHPSESSID] diff --git a/ext/sqlite/tests/sqlite_closures_001.phpt b/ext/sqlite/tests/sqlite_closures_001.phpt new file mode 100755 index 0000000000..af53e21932 --- /dev/null +++ b/ext/sqlite/tests/sqlite_closures_001.phpt @@ -0,0 +1,54 @@ +--TEST-- +sqlite: aggregate functions with closures +--INI-- +sqlite.assoc_case=0 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + unicode(11) "onetwothree" +} +DONE! diff --git a/ext/sqlite/tests/sqlite_closures_002.phpt b/ext/sqlite/tests/sqlite_closures_002.phpt new file mode 100755 index 0000000000..d11b42283d --- /dev/null +++ b/ext/sqlite/tests/sqlite_closures_002.phpt @@ -0,0 +1,52 @@ +--TEST-- +sqlite: regular functions with closures +--INI-- +sqlite.assoc_case=0 +--SKIPIF-- + +--FILE-- + +--EXPECT-- +array(1) { + [0]=> + unicode(7) "one-uno" +} +array(1) { + [0]=> + unicode(7) "two-dos" +} +array(1) { + [0]=> + unicode(10) "three-tres" +} +DONE! diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index d78ccce60b..7b372d8597 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -5390,6 +5390,10 @@ static int user_tick_function_compare(user_tick_function_entry * tick_fe1, user_ zval result; zend_compare_arrays(&result, func1, func2 TSRMLS_CC); ret = (Z_LVAL(result) == 0); + } else if (Z_TYPE_P(func1) == IS_OBJECT && Z_TYPE_P(func2) == IS_OBJECT) { + zval result; + zend_compare_objects(&result, func1, func2 TSRMLS_CC); + ret = (Z_LVAL(result) == 0); } else { ret = 0; } @@ -6109,7 +6113,7 @@ PHP_FUNCTION(register_tick_function) RETURN_FALSE; } - if (Z_TYPE_P(tick_fe.arguments[0]) != IS_ARRAY) { + if (Z_TYPE_P(tick_fe.arguments[0]) != IS_ARRAY && Z_TYPE_P(tick_fe.arguments[0]) != IS_OBJECT) { convert_to_text_ex(&tick_fe.arguments[0]); } diff --git a/ext/standard/tests/assert/assert_closures.phpt b/ext/standard/tests/assert/assert_closures.phpt new file mode 100755 index 0000000000..e01c11ace9 --- /dev/null +++ b/ext/standard/tests/assert/assert_closures.phpt @@ -0,0 +1,16 @@ +--TEST-- +assert() - basic - accept closures as callback. +--INI-- +assert.active = 1 +assert.warning = 1 +assert.bail = 0 +assert.quiet_eval = 0 +--FILE-- + +--EXPECTF-- +Hello World! + +Warning: assert(): Assertion failed in %s on line %d diff --git a/ext/standard/tests/general_functions/closures_001.phpt b/ext/standard/tests/general_functions/closures_001.phpt new file mode 100755 index 0000000000..b4fc898fd2 --- /dev/null +++ b/ext/standard/tests/general_functions/closures_001.phpt @@ -0,0 +1,11 @@ +--TEST-- +register_shutdown_function() & closure +--FILE-- + +--EXPECTF-- +Done +Hello World! diff --git a/ext/standard/tests/general_functions/closures_002.phpt b/ext/standard/tests/general_functions/closures_002.phpt new file mode 100755 index 0000000000..6df389bbb1 --- /dev/null +++ b/ext/standard/tests/general_functions/closures_002.phpt @@ -0,0 +1,25 @@ +--TEST-- +register_tick_function() & closure +--FILE-- + +--EXPECTF-- +Test +%d +%d +bool(true) +%d +Done diff --git a/ext/standard/tests/general_functions/ob_start_closures.phpt b/ext/standard/tests/general_functions/ob_start_closures.phpt new file mode 100755 index 0000000000..ba730961bd --- /dev/null +++ b/ext/standard/tests/general_functions/ob_start_closures.phpt @@ -0,0 +1,39 @@ +--TEST-- +Test ob_start() function : closures as output handlers +--INI-- +output_buffering=0 +--FILE-- + +===DONE=== +--EXPECT-- +*** Testing ob_start() : closures as output handlers *** +Output (1): Output (2): Test +With newlines +Test +With newlines +Output (2): Test +With newlines +===DONE=== diff --git a/ext/xml/tests/xml_closures_001.phpt b/ext/xml/tests/xml_closures_001.phpt new file mode 100755 index 0000000000..5439a2a918 --- /dev/null +++ b/ext/xml/tests/xml_closures_001.phpt @@ -0,0 +1,47 @@ +--TEST-- +XML parser test using closures as callbacks +--SKIPIF-- + +--INI-- +magic_quotes_runtime=0 +--FILE-- +\n"; +}; + +$end_element = function ($xp, $elem) +{ + print "\n"; +}; + +$xp = xml_parser_create(); +xml_parser_set_option($xp, XML_OPTION_CASE_FOLDING, false); +xml_set_element_handler($xp, $start_element, $end_element); +$fp = fopen("xmltest.xml", "r"); +while ($data = fread($fp, 4096)) { + xml_parse($xp, $data, feof($fp)); +} +xml_parser_free($xp); + +?> +--EXPECT-- + + + + + + + + + + diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 1adf5b3b9b..a4c903c74b 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -515,7 +515,7 @@ static void xml_set_handler(zval **handler, zval **data TSRMLS_DC) } /* IS_ARRAY might indicate that we're using array($obj, 'method') syntax */ - if (Z_TYPE_PP(data) != IS_ARRAY) { + if (Z_TYPE_PP(data) != IS_ARRAY && Z_TYPE_PP(data) != IS_OBJECT) { convert_to_text_ex(data); if (((Z_TYPE_PP(data)==IS_UNICODE) && (Z_USTRLEN_PP(data) == 0)) || ((Z_TYPE_PP(data)==IS_STRING) && (Z_STRLEN_PP(data) == 0))) {