]> granicus.if.org Git - php/commitdiff
Add str_starts_with() and str_ends_with()
authorWilliam Hudgins <will@wkhudgins.info>
Tue, 5 May 2020 13:57:39 +0000 (15:57 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 5 May 2020 14:03:47 +0000 (16:03 +0200)
RFC: https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions

Closes GH-5300.

UPGRADING
ext/standard/basic_functions.stub.php
ext/standard/basic_functions_arginfo.h
ext/standard/string.c
ext/standard/tests/strings/str_ends_with.phpt [new file with mode: 0644]
ext/standard/tests/strings/str_starts_with.phpt [new file with mode: 0644]

index 668b3dd59b6dc2fc46290d084ca9927de7f81368..233f78fdae7ccfd879d27b9edaa38db1b69e5acd 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -568,9 +568,16 @@ PHP 8.0 UPGRADE NOTES
     PR: https://github.com/php/php-src/pull/4797
 
 - Standard:
-  . Added str_contains($haystack, $needle) function, which checks whether
-    $haystack contains $needle as a sub-string. It is equivalent to writing
-    strpos($haystack, $needle) !== false.
+  . Added
+
+        str_contains(string $haystack, string $needle): bool
+        str_starts_with(string $haystack, string $needle): bool
+        str_ends_with(string $haystack, string $needle): bool
+
+    functions, which check whether $haystack contains, starts with or ends with
+    $needle.
+    RFC: https://wiki.php.net/rfc/str_contains
+    RFC: https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions
   . Added fdiv() function, which performs a floating-point division under
     IEEE 754 semantics. Division by zero is considered well-defined and
     will return one of Inf, -Inf or NaN.
index e750d2229c067e6e1b6a82a248b2eaa3ef3a1b80..2017549e9b55a4465afd5c1b92b7509aa8525ecf 100755 (executable)
@@ -604,6 +604,10 @@ function strrchr(string $haystack, string $needle): string|false {}
 
 function str_contains(string $haystack, string $needle): bool {}
 
+function str_starts_with(string $haystack, string $needle): bool {}
+
+function str_ends_with(string $haystack, string $needle): bool {}
+
 function chunk_split(string $str, int $chunklen = 76, string $ending = "\r\n"): string {}
 
 function substr(string $str, int $start, ?int $length = null): string|false {}
index f7c98056834e58f4afcb8f9a713ab6ff54663d5b..5e2e457ea286e1bc8a682cbba5c1f28e4552f6f1 100755 (executable)
@@ -923,6 +923,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_str_contains, 0, 2, _IS_BOOL, 0)
        ZEND_ARG_TYPE_INFO(0, needle, IS_STRING, 0)
 ZEND_END_ARG_INFO()
 
+#define arginfo_str_starts_with arginfo_str_contains
+
+#define arginfo_str_ends_with arginfo_str_contains
+
 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_chunk_split, 0, 1, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
        ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, chunklen, IS_LONG, 0, "76")
@@ -2496,6 +2500,8 @@ ZEND_FUNCTION(strrpos);
 ZEND_FUNCTION(strripos);
 ZEND_FUNCTION(strrchr);
 ZEND_FUNCTION(str_contains);
+ZEND_FUNCTION(str_starts_with);
+ZEND_FUNCTION(str_ends_with);
 ZEND_FUNCTION(chunk_split);
 ZEND_FUNCTION(substr);
 ZEND_FUNCTION(substr_replace);
@@ -3129,6 +3135,8 @@ static const zend_function_entry ext_functions[] = {
        ZEND_FE(strripos, arginfo_strripos)
        ZEND_FE(strrchr, arginfo_strrchr)
        ZEND_FE(str_contains, arginfo_str_contains)
+       ZEND_FE(str_starts_with, arginfo_str_starts_with)
+       ZEND_FE(str_ends_with, arginfo_str_ends_with)
        ZEND_FE(chunk_split, arginfo_chunk_split)
        ZEND_FE(substr, arginfo_substr)
        ZEND_FE(substr_replace, arginfo_substr_replace)
index c2e9fe3c276d81e50fc8b688c31fda13103a714d..5b0df571d6717e303a9769ba11767bfad8d4fffb 100644 (file)
@@ -1864,6 +1864,44 @@ PHP_FUNCTION(str_contains)
 }
 /* }}} */
 
+/* {{{ proto bool str_starts_with(string haystack, string needle)
+   Checks if haystack starts with needle */
+PHP_FUNCTION(str_starts_with)
+{
+       zend_string *haystack, *needle;
+
+       ZEND_PARSE_PARAMETERS_START(2, 2)
+               Z_PARAM_STR(haystack)
+               Z_PARAM_STR(needle)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
+               RETURN_FALSE;
+       }
+
+       RETURN_BOOL(memcmp(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
+}
+
+/* {{{ proto bool str_ends_with(string haystack, string needle)
+   Checks if haystack ends with needle */
+PHP_FUNCTION(str_ends_with)
+{
+       zend_string *haystack, *needle;
+
+       ZEND_PARSE_PARAMETERS_START(2, 2)
+               Z_PARAM_STR(haystack)
+               Z_PARAM_STR(needle)
+       ZEND_PARSE_PARAMETERS_END();
+
+       if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
+               RETURN_FALSE;
+       }
+
+       RETURN_BOOL(memcmp(
+               ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - ZSTR_LEN(needle),
+               ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
+}
+
 /* {{{ proto string strchr(string haystack, string needle)
    An alias for strstr */
 /* }}} */
diff --git a/ext/standard/tests/strings/str_ends_with.phpt b/ext/standard/tests/strings/str_ends_with.phpt
new file mode 100644 (file)
index 0000000..8aa5f0a
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+str_ends_with() function - unit tests for str_ends_with()
+--FILE--
+<?php
+/* Prototype: bool str_ends_with (string $haystack, string $needle);
+   Description: Determine if $haystack ends with $needle
+*/
+$testStr = "beginningMiddleEnd";
+var_dump(str_ends_with($testStr, "End"));
+var_dump(str_ends_with($testStr, "end"));
+var_dump(str_ends_with($testStr, "en"));
+var_dump(str_ends_with($testStr, $testStr));
+var_dump(str_ends_with($testStr, $testStr.$testStr));
+var_dump(str_ends_with($testStr, ""));
+var_dump(str_ends_with("", ""));
+var_dump(str_ends_with("", " "));
+var_dump(str_ends_with($testStr, "\x00"));
+var_dump(str_ends_with("\x00", ""));
+var_dump(str_ends_with("\x00", "\x00"));
+var_dump(str_ends_with("a\x00", "\x00"));
+var_dump(str_ends_with("ab\x00c", "b\x00c"));
+var_dump(str_ends_with("a\x00b", "d\x00b"));
+var_dump(str_ends_with("a\x00b", "a\x00z"));
+var_dump(str_ends_with("a", "\x00a"));
+var_dump(str_ends_with("a", "a\x00"));
+?>
+--EXPECT--
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)
diff --git a/ext/standard/tests/strings/str_starts_with.phpt b/ext/standard/tests/strings/str_starts_with.phpt
new file mode 100644 (file)
index 0000000..776d945
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+str_starts_with() function - unit tests for str_starts_with()
+--FILE--
+<?php
+/* Prototype: bool str_starts_with (string $haystack, string $needle);
+   Description: Determine if $haystack begins with $needle
+*/
+$testStr = "beginningMiddleEnd";
+var_dump(str_starts_with($testStr, "beginning"));
+var_dump(str_starts_with($testStr, "Beginning"));
+var_dump(str_starts_with($testStr, "eginning"));
+var_dump(str_starts_with($testStr, $testStr));
+var_dump(str_starts_with($testStr, $testStr.$testStr));
+var_dump(str_starts_with($testStr, ""));
+var_dump(str_starts_with("", ""));
+var_dump(str_starts_with("", " "));
+var_dump(str_starts_with($testStr, "\x00"));
+var_dump(str_starts_with("\x00", ""));
+var_dump(str_starts_with("\x00", "\x00"));
+var_dump(str_starts_with("\x00a", "\x00"));
+var_dump(str_starts_with("a\x00bc", "a\x00b"));
+var_dump(str_starts_with("a\x00b", "a\x00d"));
+var_dump(str_starts_with("a\x00b", "z\x00b"));
+var_dump(str_starts_with("a", "a\x00"));
+var_dump(str_starts_with("a", "\x00a"));
+?>
+--EXPECT--
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(false)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(false)
+bool(false)
+bool(false)
+bool(false)