Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save sirreal/0fc67d8d330a3124a665c242113b42f0 to your computer and use it in GitHub Desktop.

Select an option

Save sirreal/0fc67d8d330a3124a665c242113b42f0 to your computer and use it in GitHub Desktop.
PHP String Comparison Benchmarks

PHP String Comparison Benchmark Results

Performance comparison of different string matching methods in PHP.

Case-Sensitive Comparison Results

Test Setup:

  • String length: 76,000 bytes
  • Iterations: 1000 per method
  • Each test run was a separate, sequential php CLI call to minimize interference
php benchmark.php char-by-char
php benchmark.php substr-compare
php benchmark.php substr-equals
php benchmark.php char-by-char-ci
php benchmark.php substr-compare-ci
php benchmark.php strncasecmp
php benchmark.php strtolower-substr

Results

Method Time (seconds)
substr with === 1.56
substr_compare 1.82
Character-by-character 1.91

Code Examples

substr with === :

if ('SYSTEM' === substr($string, $at, 6)) {
    // match found
}

substr_compare:

if (0 === substr_compare($string, 'SYSTEM', $at, 6)) {
    // match found
}

Character-by-character:

if (
    'S' === $string[$at] &&
    'Y' === $string[$at + 1] &&
    'S' === $string[$at + 2] &&
    'T' === $string[$at + 3] &&
    'E' === $string[$at + 4] &&
    'M' === $string[$at + 5]
) {
    // match found
}

Case-Insensitive Comparison Results

Test Setup:

  • String length: 83,000 bytes
  • Iterations: 1,000 per method
  • Each method tested independently
  • Mixed case test string with SYSTEM, SyStEm, system, SySteM

Results

Method Time (seconds)
substr_compare(..., true) 2.46
strtolower(substr()) === 2.90
Character-by-character (OR) 3.34
strncasecmp() 38.94

Code Examples

substr_compare with case-insensitive flag:

if (0 === substr_compare($string, 'SYSTEM', $at, 6, true)) {
    // match found
}

strtolower(substr()) ===:

if ('system' === strtolower(substr($string, $at, 6))) {
    // match found
}

Character-by-character with OR checks:

if (
    ('S' === $string[$at] || 's' === $string[$at]) &&
    ('Y' === $string[$at + 1] || 'y' === $string[$at + 1]) &&
    ('S' === $string[$at + 2] || 's' === $string[$at + 2]) &&
    ('T' === $string[$at + 3] || 't' === $string[$at + 3]) &&
    ('E' === $string[$at + 4] || 'e' === $string[$at + 4]) &&
    ('M' === $string[$at + 5] || 'm' === $string[$at + 5])
) {
    // match found
}

strncasecmp():

if (0 === strncasecmp(substr($string, $at), 'SYSTEM', 6)) {
    // match found
}

Test Environment

  • PHP Version: (detected from system)
  • Platform: macOS (Darwin 24.6.0)
  • Test Date: 2025-11-02

Methodology

  • Each benchmark script runs only one comparison method to minimize interference
  • Tests were run sequentially, not simultaneously
<?php
/**
* Consolidated String Comparison Benchmark
*
* Usage: php benchmark.php <method>
*
* Methods:
* char-by-char Character-by-character (case-sensitive)
* substr-compare substr_compare() (case-sensitive)
* substr-equals substr() with === (case-sensitive)
* char-by-char-ci Character-by-character (case-insensitive)
* substr-compare-ci substr_compare() with case-insensitive flag
* strncasecmp strncasecmp() (case-insensitive)
* strtolower-substr strtolower(substr()) === (case-insensitive)
*/
// Configuration.
$config = array(
'case_sensitive' => array(
'test_string' => str_repeat( 'Lorem ipsum SYSTEM dolor sit amet SYSTEM consectetur SYSTEM adipiscing elit ', 1000 ),
'iterations' => 1000,
),
'case_insensitive' => array(
'test_string' => str_repeat( 'Lorem ipsum SYSTEM dolor sit SyStEm amet system consectetur SySteM adipiscing elit ', 1000 ),
'iterations' => 1000,
),
);
// Benchmark methods.
$methods = array(
'char-by-char' => array(
'name' => 'Character-by-character comparison (case-sensitive)',
'case_sensitive' => true,
'function' => function ( $test_string, $iterations ) {
$matches = 0;
for ( $i = 0; $i < $iterations; $i++ ) {
for ( $at = 0; $at < strlen( $test_string ) - 6; $at++ ) {
if (
'S' === $test_string[ $at ] &&
'Y' === $test_string[ $at + 1 ] &&
'S' === $test_string[ $at + 2 ] &&
'T' === $test_string[ $at + 3 ] &&
'E' === $test_string[ $at + 4 ] &&
'M' === $test_string[ $at + 5 ]
) {
++$matches;
}
}
}
return $matches;
},
),
'substr-compare' => array(
'name' => 'substr_compare() (case-sensitive)',
'case_sensitive' => true,
'function' => function ( $test_string, $iterations ) {
$matches = 0;
for ( $i = 0; $i < $iterations; $i++ ) {
for ( $at = 0; $at < strlen( $test_string ) - 6; $at++ ) {
if ( 0 === substr_compare( $test_string, 'SYSTEM', $at, 6 ) ) {
++$matches;
}
}
}
return $matches;
},
),
'substr-equals' => array(
'name' => 'substr() with === comparison (case-sensitive)',
'case_sensitive' => true,
'function' => function ( $test_string, $iterations ) {
$matches = 0;
for ( $i = 0; $i < $iterations; $i++ ) {
for ( $at = 0; $at < strlen( $test_string ) - 6; $at++ ) {
if ( 'SYSTEM' === substr( $test_string, $at, 6 ) ) {
++$matches;
}
}
}
return $matches;
},
),
'char-by-char-ci' => array(
'name' => 'Character-by-character comparison (case-insensitive)',
'case_sensitive' => false,
'function' => function ( $test_string, $iterations ) {
$matches = 0;
for ( $i = 0; $i < $iterations; $i++ ) {
for ( $at = 0; $at < strlen( $test_string ) - 6; $at++ ) {
if (
( 'S' === $test_string[ $at ] || 's' === $test_string[ $at ] ) &&
( 'Y' === $test_string[ $at + 1 ] || 'y' === $test_string[ $at + 1 ] ) &&
( 'S' === $test_string[ $at + 2 ] || 's' === $test_string[ $at + 2 ] ) &&
( 'T' === $test_string[ $at + 3 ] || 't' === $test_string[ $at + 3 ] ) &&
( 'E' === $test_string[ $at + 4 ] || 'e' === $test_string[ $at + 4 ] ) &&
( 'M' === $test_string[ $at + 5 ] || 'm' === $test_string[ $at + 5 ] )
) {
++$matches;
}
}
}
return $matches;
},
),
'substr-compare-ci' => array(
'name' => 'substr_compare() with case-insensitive flag',
'case_sensitive' => false,
'function' => function ( $test_string, $iterations ) {
$matches = 0;
for ( $i = 0; $i < $iterations; $i++ ) {
for ( $at = 0; $at < strlen( $test_string ) - 6; $at++ ) {
if ( 0 === substr_compare( $test_string, 'SYSTEM', $at, 6, true ) ) {
++$matches;
}
}
}
return $matches;
},
),
'strncasecmp' => array(
'name' => 'strncasecmp() (case-insensitive)',
'case_sensitive' => false,
'function' => function ( $test_string, $iterations ) {
$matches = 0;
for ( $i = 0; $i < $iterations; $i++ ) {
for ( $at = 0; $at < strlen( $test_string ) - 6; $at++ ) {
if ( 0 === strncasecmp( substr( $test_string, $at ), 'SYSTEM', 6 ) ) {
++$matches;
}
}
}
return $matches;
},
),
'strtolower-substr' => array(
'name' => 'strtolower(substr()) === (case-insensitive)',
'case_sensitive' => false,
'function' => function ( $test_string, $iterations ) {
$matches = 0;
for ( $i = 0; $i < $iterations; $i++ ) {
for ( $at = 0; $at < strlen( $test_string ) - 6; $at++ ) {
if ( 'system' === strtolower( substr( $test_string, $at, 6 ) ) ) {
++$matches;
}
}
}
return $matches;
},
),
);
// Parse CLI arguments.
if ( $argc < 2 ) {
echo "Usage: php benchmark.php <method>\n\n";
echo "Available methods:\n";
foreach ( $methods as $key => $method ) {
$type = $method['case_sensitive'] ? 'case-sensitive' : 'case-insensitive';
echo " {$key}\n {$method['name']} ({$type})\n";
}
exit( 1 );
}
$selected_method = $argv[1];
if ( ! isset( $methods[ $selected_method ] ) ) {
echo "Error: Unknown method '{$selected_method}'\n";
echo "Run 'php benchmark.php' to see available methods.\n";
exit( 1 );
}
// Get configuration for this method.
$method = $methods[ $selected_method ];
$test_config = $method['case_sensitive'] ? $config['case_sensitive'] : $config['case_insensitive'];
$test_string = $test_config['test_string'];
$iterations = $test_config['iterations'];
// Display test information.
echo "Benchmarking: {$method['name']}\n";
echo 'String length: ' . number_format( strlen( $test_string ) ) . " bytes\n";
echo 'Iterations: ' . number_format( $iterations ) . "\n";
// Run benchmark.
$start = microtime( true );
$matches = $method['function']( $test_string, $iterations );
$elapsed = microtime( true ) - $start;
// Display results.
echo "\nTime: " . number_format( $elapsed, 2 ) . " seconds\n";
echo 'Matches found: ' . number_format( $matches ) . "\n";
echo "--------------------------------\n";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment