Skip to content

Commit 31fb6a0

Browse files
wkhudgins92nikic
authored andcommitted
Add str_starts_with() and str_ends_with()
RFC: https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions Closes GH-5300.
1 parent e749db4 commit 31fb6a0

File tree

6 files changed

+148
-3
lines changed

6 files changed

+148
-3
lines changed

UPGRADING

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -568,9 +568,16 @@ PHP 8.0 UPGRADE NOTES
568568
PR: https://github.com/php/php-src/pull/4797
569569

570570
- Standard:
571-
. Added str_contains($haystack, $needle) function, which checks whether
572-
$haystack contains $needle as a sub-string. It is equivalent to writing
573-
strpos($haystack, $needle) !== false.
571+
. Added
572+
573+
str_contains(string $haystack, string $needle): bool
574+
str_starts_with(string $haystack, string $needle): bool
575+
str_ends_with(string $haystack, string $needle): bool
576+
577+
functions, which check whether $haystack contains, starts with or ends with
578+
$needle.
579+
RFC: https://wiki.php.net/rfc/str_contains
580+
RFC: https://wiki.php.net/rfc/add_str_starts_with_and_ends_with_functions
574581
. Added fdiv() function, which performs a floating-point division under
575582
IEEE 754 semantics. Division by zero is considered well-defined and
576583
will return one of Inf, -Inf or NaN.

ext/standard/basic_functions.stub.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -604,6 +604,10 @@ function strrchr(string $haystack, string $needle): string|false {}
604604

605605
function str_contains(string $haystack, string $needle): bool {}
606606

607+
function str_starts_with(string $haystack, string $needle): bool {}
608+
609+
function str_ends_with(string $haystack, string $needle): bool {}
610+
607611
function chunk_split(string $str, int $chunklen = 76, string $ending = "\r\n"): string {}
608612

609613
function substr(string $str, int $start, ?int $length = null): string|false {}

ext/standard/basic_functions_arginfo.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_str_contains, 0, 2, _IS_BOOL, 0)
923923
ZEND_ARG_TYPE_INFO(0, needle, IS_STRING, 0)
924924
ZEND_END_ARG_INFO()
925925

926+
#define arginfo_str_starts_with arginfo_str_contains
927+
928+
#define arginfo_str_ends_with arginfo_str_contains
929+
926930
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_chunk_split, 0, 1, IS_STRING, 0)
927931
ZEND_ARG_TYPE_INFO(0, str, IS_STRING, 0)
928932
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, chunklen, IS_LONG, 0, "76")
@@ -2496,6 +2500,8 @@ ZEND_FUNCTION(strrpos);
24962500
ZEND_FUNCTION(strripos);
24972501
ZEND_FUNCTION(strrchr);
24982502
ZEND_FUNCTION(str_contains);
2503+
ZEND_FUNCTION(str_starts_with);
2504+
ZEND_FUNCTION(str_ends_with);
24992505
ZEND_FUNCTION(chunk_split);
25002506
ZEND_FUNCTION(substr);
25012507
ZEND_FUNCTION(substr_replace);
@@ -3129,6 +3135,8 @@ static const zend_function_entry ext_functions[] = {
31293135
ZEND_FE(strripos, arginfo_strripos)
31303136
ZEND_FE(strrchr, arginfo_strrchr)
31313137
ZEND_FE(str_contains, arginfo_str_contains)
3138+
ZEND_FE(str_starts_with, arginfo_str_starts_with)
3139+
ZEND_FE(str_ends_with, arginfo_str_ends_with)
31323140
ZEND_FE(chunk_split, arginfo_chunk_split)
31333141
ZEND_FE(substr, arginfo_substr)
31343142
ZEND_FE(substr_replace, arginfo_substr_replace)

ext/standard/string.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1864,6 +1864,44 @@ PHP_FUNCTION(str_contains)
18641864
}
18651865
/* }}} */
18661866

1867+
/* {{{ proto bool str_starts_with(string haystack, string needle)
1868+
Checks if haystack starts with needle */
1869+
PHP_FUNCTION(str_starts_with)
1870+
{
1871+
zend_string *haystack, *needle;
1872+
1873+
ZEND_PARSE_PARAMETERS_START(2, 2)
1874+
Z_PARAM_STR(haystack)
1875+
Z_PARAM_STR(needle)
1876+
ZEND_PARSE_PARAMETERS_END();
1877+
1878+
if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
1879+
RETURN_FALSE;
1880+
}
1881+
1882+
RETURN_BOOL(memcmp(ZSTR_VAL(haystack), ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
1883+
}
1884+
1885+
/* {{{ proto bool str_ends_with(string haystack, string needle)
1886+
Checks if haystack ends with needle */
1887+
PHP_FUNCTION(str_ends_with)
1888+
{
1889+
zend_string *haystack, *needle;
1890+
1891+
ZEND_PARSE_PARAMETERS_START(2, 2)
1892+
Z_PARAM_STR(haystack)
1893+
Z_PARAM_STR(needle)
1894+
ZEND_PARSE_PARAMETERS_END();
1895+
1896+
if (ZSTR_LEN(needle) > ZSTR_LEN(haystack)) {
1897+
RETURN_FALSE;
1898+
}
1899+
1900+
RETURN_BOOL(memcmp(
1901+
ZSTR_VAL(haystack) + ZSTR_LEN(haystack) - ZSTR_LEN(needle),
1902+
ZSTR_VAL(needle), ZSTR_LEN(needle)) == 0);
1903+
}
1904+
18671905
/* {{{ proto string strchr(string haystack, string needle)
18681906
An alias for strstr */
18691907
/* }}} */
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
str_ends_with() function - unit tests for str_ends_with()
3+
--FILE--
4+
<?php
5+
/* Prototype: bool str_ends_with (string $haystack, string $needle);
6+
Description: Determine if $haystack ends with $needle
7+
*/
8+
$testStr = "beginningMiddleEnd";
9+
var_dump(str_ends_with($testStr, "End"));
10+
var_dump(str_ends_with($testStr, "end"));
11+
var_dump(str_ends_with($testStr, "en"));
12+
var_dump(str_ends_with($testStr, $testStr));
13+
var_dump(str_ends_with($testStr, $testStr.$testStr));
14+
var_dump(str_ends_with($testStr, ""));
15+
var_dump(str_ends_with("", ""));
16+
var_dump(str_ends_with("", " "));
17+
var_dump(str_ends_with($testStr, "\x00"));
18+
var_dump(str_ends_with("\x00", ""));
19+
var_dump(str_ends_with("\x00", "\x00"));
20+
var_dump(str_ends_with("a\x00", "\x00"));
21+
var_dump(str_ends_with("ab\x00c", "b\x00c"));
22+
var_dump(str_ends_with("a\x00b", "d\x00b"));
23+
var_dump(str_ends_with("a\x00b", "a\x00z"));
24+
var_dump(str_ends_with("a", "\x00a"));
25+
var_dump(str_ends_with("a", "a\x00"));
26+
?>
27+
--EXPECT--
28+
bool(true)
29+
bool(false)
30+
bool(false)
31+
bool(true)
32+
bool(false)
33+
bool(true)
34+
bool(true)
35+
bool(false)
36+
bool(false)
37+
bool(true)
38+
bool(true)
39+
bool(true)
40+
bool(true)
41+
bool(false)
42+
bool(false)
43+
bool(false)
44+
bool(false)
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
str_starts_with() function - unit tests for str_starts_with()
3+
--FILE--
4+
<?php
5+
/* Prototype: bool str_starts_with (string $haystack, string $needle);
6+
Description: Determine if $haystack begins with $needle
7+
*/
8+
$testStr = "beginningMiddleEnd";
9+
var_dump(str_starts_with($testStr, "beginning"));
10+
var_dump(str_starts_with($testStr, "Beginning"));
11+
var_dump(str_starts_with($testStr, "eginning"));
12+
var_dump(str_starts_with($testStr, $testStr));
13+
var_dump(str_starts_with($testStr, $testStr.$testStr));
14+
var_dump(str_starts_with($testStr, ""));
15+
var_dump(str_starts_with("", ""));
16+
var_dump(str_starts_with("", " "));
17+
var_dump(str_starts_with($testStr, "\x00"));
18+
var_dump(str_starts_with("\x00", ""));
19+
var_dump(str_starts_with("\x00", "\x00"));
20+
var_dump(str_starts_with("\x00a", "\x00"));
21+
var_dump(str_starts_with("a\x00bc", "a\x00b"));
22+
var_dump(str_starts_with("a\x00b", "a\x00d"));
23+
var_dump(str_starts_with("a\x00b", "z\x00b"));
24+
var_dump(str_starts_with("a", "a\x00"));
25+
var_dump(str_starts_with("a", "\x00a"));
26+
?>
27+
--EXPECT--
28+
bool(true)
29+
bool(false)
30+
bool(false)
31+
bool(true)
32+
bool(false)
33+
bool(true)
34+
bool(true)
35+
bool(false)
36+
bool(false)
37+
bool(true)
38+
bool(true)
39+
bool(true)
40+
bool(true)
41+
bool(false)
42+
bool(false)
43+
bool(false)
44+
bool(false)

0 commit comments

Comments
 (0)