BAB 7: STRING MANIPULATION

7-4: String Comparison

Objectives

  • String comparison functions
  • Natural sorting
  • Similarity
  • Memahami operator ==, ===, dan <=>
  • Mengenal version_compare dan keamanan output

Kenapa Perlu Membandingkan String?

Program sehari-hari penuh dengan perbandingan string: cek password, cek username, urutkan daftar nama, cari kata mirip untuk saran pencarian, sampai membandingkan versi aplikasi. PHP menyediakan banyak cara — dari operator sampai function khusus — dan masing-masing punya perilaku yang berbeda.

KebutuhanCara
Sama persis?===, strcmp()
Sama (abaikan case)?strcasecmp()
Urutan alfabet?strcmp(), <=>
Mirip?similar_text(), levenshtein()
Versi software?version_compare()

Operator Perbandingan

Cara paling dasar membandingkan string adalah dengan operator:

php
<?php

$a = "apple";
$b = "apple";
$c = "Apple";

// ==  : sama (case-sensitive)
var_dump($a == $b);   // Output: bool(true)
var_dump($a == $c);   // Output: bool(false) — "apple" vs "Apple"

// === : sama dan tipe sama (string sama string)
var_dump($a === $b);  // Output: bool(true)

// != dan !== : kebalikannya
var_dump($a != $c);   // Output: bool(true)
var_dump($a !== $b);  // Output: bool(false)

?>
💡Tip

Untuk string, == dan === hasilnya sama — string selalu string. Bedanya terasa saat membandingkan string dengan angka: "10" == 10 itu true (loose), tapi "10" === 10 itu false.

Spaceship Operator (<=>)

PHP 7+ punya operator <=> yang mengembalikan tiga kemungkinan nilai:

HasilArti
-1Nilai kiri lebih kecil
0Sama
1Nilai kiri lebih besar
php
<?php

echo "apple" <=> "banana";  // -1 (apple < banana)
echo "banana" <=> "apple";  // 1  (banana > apple)
echo "apple" <=> "apple";   // 0  (sama)

// Sangat berguna untuk callback sorting:
$buah = ["mangga", "apel", "jeruk", "pisang"];

usort($buah, fn($x, $y) => $x <=> $y);
print_r($buah);
// Output: ["apel", "jeruk", "mangga", "pisang"]

// Urutkan menurun: balik arahnya
usort($buah, fn($x, $y) => $y <=> $x);
print_r($buah);
// Output: ["pisang", "mangga", "jeruk", "apel"]

?>

Basic Comparison (Function)

Operator ==/=== hanya memberi tahu "sama atau tidak". Kalau kamu butuh urutan (mana yang lebih besar), gunakan strcmp:

php
<?php

$a = "apple";
$b = "banana";

// strcmp - binary safe
strcmp($a, $b);   // < 0 (a < b)
strcmp($b, $a);   // > 0 (b > a)
strcmp($a, $a);   // 0 (equal)

// Case-insensitive
strcasecmp($a, "APPLE");  // 0

// First n characters
strncmp($a, $b, 3);  // Compare first 3 chars

?>
FungsiMembandingkanCase-sensitiveKeterangan
strcmp($a, $b)Seluruh string✅ YaBinary safe
strcasecmp($a, $b)Seluruh string❌ TidakAbaikan besar/kecil
strncmp($a, $b, $n)$n karakter pertama✅ YaPartial
strncasecmp($a, $b, $n)$n karakter pertama❌ TidakPartial + case-insensitive

Mengapa Hasilnya Bisa Negatif?

strcmp membandingkan berdasarkan nilai byte karakter: huruf kecil (a = 97) lebih besar dari huruf besar (A = 65). Perhatikan:

php
<?php

echo strcmp("apple", "Apple");  // 32 (a=97 vs A=65, selisih 32)
echo strcmp("a", "b");          // -1  (a < b)
echo strcmp("b", "a");          // 1   (b > a)

// "10" vs "9": karena string, bukan angka!
echo strcmp("10", "9");         // -8  ('1'=49 vs '9'=57, selisih -8)
echo (10 <=> 9);                // 1   (10 > 9 secara angka)

?>
⚠️Perhatian

strcmp membandingkan secara string, bukan numerik. strcmp("10", "9") menghasilkan -1 karena karakter '1' lebih kecil dari '9'. Untuk angka, bandingkan sebagai angka (atau gunakan version_compare untuk versi).

Contoh Nyata: Sortir dengan strcmp

php
<?php

$nama = ["Budi", "andi", "Citra", "Andi"];

// sort() default: case-sensitive, huruf besar dulu
sort($nama);
print_r($nama);
// Output: ["Andi", "Budi", "Citra", "andi"]

// Dengan strcasecmp: abaikan case -> urutan alfabet murni
usort($nama, "strcasecmp");
print_r($nama);
// Output: ["andi", "Andi", "Budi", "Citra"]

?>

Natural Sorting

Sortir biasa (ASCII/byte order) menghasilkan urutan yang "aneh" untuk data berangka: file10 datang sebelum file2 karena '1' < '2'. Natural sort memperlakukan angka sebagai angka:

php
<?php

$files = ["file1.txt", "file10.txt", "file2.txt", "file21.txt"];

// Regular sort
sort($files);
print_r($files);  
// file1.txt, file10.txt, file2.txt, file21.txt (ASCII order)

// Natural sort
natcasesort($files);
print_r($files);  
// file1.txt, file2.txt, file10.txt, file21.txt (human order)

?>
FungsiPerilaku
sort()Urutan byte/ASCII, file10 sebelum file2
natsort()Natural, case-sensitive
natcasesort()Natural, case-insensitive — paling sering dipakai
php
<?php

// natsort mengubah key array — reset dengan array_values
$versi = ["v1.10", "v1.9", "v1.2", "v2.0"];

natcasesort($versi);
$versi = array_values($versi);  // rapi ulang index

print_r($versi);
// Output: ["v1.2", "v1.9", "v1.10", "v2.0"]

?>
💡Tip

Gunakan natcasesort untuk daftar file, nama produk dengan angka (Produk 2, Produk 10), atau versi — hasilnya sesuai intuisi manusia.

version_compare untuk Versi Software

Untuk membandingkan versi dengan benar (1.10 > 1.9), jangan pakai strcmp:

php
<?php

// version_compare($v1, $v2) -> -1, 0, atau 1
echo version_compare("1.10", "1.9");   // 1  (1.10 lebih baru)
echo version_compare("2.0", "2.0");     // 0  (sama)
echo version_compare("1.0", "1.1");     // -1 (1.0 lebih lama)

// Operator string juga didukung:
if (version_compare(PHP_VERSION, "8.0", ">=")) {
    echo "Pakai match expression!";  // Output: Pakai match expression!
}

// Cocok untuk cek minimum requirement:
$requirement = "8.1";
if (version_compare(PHP_VERSION, $requirement, ">=")) {
    echo "PHP kamu mendukung fitur ini";
} else {
    echo "Upgrade PHP minimal $requirement";
}

?>

String Similarity

Kadang kita butuh mengukur seberapa mirip dua string — misalnya untuk fitur "mungkin maksudmu...":

php
<?php

$word1 = "PHP";
$word2 = "PHP";

similar_text($word1, $word2, $percent);
echo $percent;  // 100

similar_text("PHP", "PHP", $p);   // 100
similar_text("PHP", "PhP", $p);   // ~66.67 (case-insensitive by default)

similar_text("hello", "helo", $p);  // Different lengths

// Levenshtein distance
levenshtein("hello", "helo");  // 1 (one character difference)

?>

similar_text vs levenshtein

FungsiArti hasilKasus pakai
similar_textPersentase kemiripan (0-100)Saran "apakah maksudmu?"
levenshteinJumlah edit minimal (ganti/tambah/hapus)Deteksi typo, autocorrect
php
<?php

$kata = "teknilogi";  // typo, seharusnya "teknologi"

$kandidat = ["teknologi", "teknisi", "teknik"];

// Cari kandidat dengan jarak Levenshtein terkecil
$terbaik = null;
$jarak_terkecil = PHP_INT_MAX;

foreach ($kandidat as $c) {
    $jarak = levenshtein($kata, $c);
    if ($jarak < $jarak_terkecil) {
        $jarak_terkecil = $jarak;
        $terbaik = $c;
    }
}

echo "Mungkin maksudmu: $terbaik (jarak $jarak_terkecil)";
// Output: Mungkin maksudmu: teknologi (jarak 1)

?>
💡Tip

levenshtein hanya bekerja untuk string ASCII. Untuk teks multibyte atau kebutuhan fuzzy search yang serius, pertimbangkan library seperti nlpTools atau pencarian full-text di database.

htmlspecialchars()

Saat menampilkan input user di halaman HTML, string bisa mengandung tag yang berbahaya. htmlspecialchars mengubah karakter khusus menjadi entity HTML sehingga browser menampilkannya sebagai teks biasa:

php
<?php

$user_input = '<script>alert("XSS")</script>';

// Escape HTML untuk output
$safe = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
echo $safe;
// Output: &lt;script&gt;alert(&quot;XSS&quot;)&lt;/script&gt;

?>

Karakter yang di-escape:

KarakterMenjadiAlasan
<&lt;Mencegah tag HTML dibaca
>&gt;Mencegah penutup tag
&&amp;Mencegah entity palsu
"&quot; (dengan ENT_QUOTES)Melindungi atribut HTML
'&#039; (dengan ENT_QUOTES)Melindungi atribut HTML
php
<?php

// Contoh di dunia nyata: komentar user
$komentar = "Bagus! <b>coba</b> <script>alert('x')</script>";

// ❌ Berbahaya: tag <script> akan dieksekusi browser
// echo $komentar;

// ✅ Aman: semua tag jadi teks biasa
echo htmlspecialchars($komentar, ENT_QUOTES, 'UTF-8');
// Output: Bagus! &lt;b&gt;coba&lt;/b&gt; &lt;script&gt;alert(&#039;x&#039;)&lt;/script&gt;

?>
⚠️Perhatian

Security: SELALU escape user input dengan htmlspecialchars() sebelum menampilkan di HTML untuk mencegah XSS attacks. Aturan emasnya: escape saat output, bukan saat input — karena konteks output menentukan escape yang tepat.

htmlspecialchars vs htmlentities vs strip_tags

FungsiPerilakuKapan
htmlspecialcharsEscape 5 karakter khususDefault choice untuk output user
htmlentitiesEscape semua karakter yang punya entityTeks dengan banyak simbol khusus
strip_tagsHapus tag (bukan escape)Ingin teks polos tanpa HTML
php
<?php

$teks = "<p>Harga: Rp 50.000 & gratis ongkir</p>";

// htmlspecialchars: cukup untuk keamanan
echo htmlspecialchars($teks, ENT_QUOTES, 'UTF-8');
// Output: &lt;p&gt;Harga: Rp 50.000 &amp; gratis ongkir&lt;/p&gt;

// strip_tags: buang tag, sisakan teks
echo strip_tags($teks);
// Output: Harga: Rp 50.000 & gratis ongkir

?>
💡Tip

Untuk output HTML yang aman, htmlspecialchars sudah cukup — tidak perlu htmlentities yang lebih berat. Yang wajib di-escape: <, >, &, dan kutip (jika di dalam atribut).

Common Mistakes

Mistake 1: Membandingkan string dengan == padahal butuh urutan

php
<?php

$kata1 = "pear";
$kata2 = "peach";

// == hanya jawab "sama/tidak"
var_dump($kata1 == $kata2);  // bool(false)

// Untuk urutan, pakai strcmp / <=>
echo strcmp($kata1, $kata2);  // 2 ("pear" > "peach" di karakter ke-3)
echo $kata1 <=> $kata2;       // 1

?>

Mistake 2: Mengira strcmp mengembalikan boolean

php
<?php

// ❌ Salah: strcmp mengembalikan angka, bukan true/false
if (strcmp($a, $b)) {
    // Ini jalan SAAT KEDUANYA BEDA (hasil != 0)
    // — kebalikan dari yang mungkin kamu kira!
}

// ✅ Benar: bandingkan hasilnya dengan 0
if (strcmp($a, $b) === 0) {
    // Sama
}

// Atau lebih sederhana untuk sekadar cek sama:
if ($a === $b) {
    // Sama
}

?>
⚠️Perhatian

strcmp mengembalikan angka, bukan boolean — 0 artinya sama. if (strcmp($a, $b)) bernilai true justru saat string berbeda! Untuk sekadar cek kesamaan, === jauh lebih jelas.

Mistake 3: Menampilkan user input tanpa escape

php
<?php

// ❌ XSS vulnerability!
// echo $_GET["nama"];

// ✅ Aman
echo htmlspecialchars($_GET["nama"] ?? "", ENT_QUOTES, 'UTF-8');

?>

Mistake 4: Mengurutkan angka sebagai string

php
<?php

$nilai = ["10", "9", "100", "2"];

// ❌ Urutan string: "10" < "2" karena '1' < '2'
sort($nilai);
print_r($nilai);
// Output: ["10", "100", "2", "9"]

// ✅ Urutan natural: angka dibaca sebagai angka
natcasesort($nilai);
print_r(array_values($nilai));
// Output: ["2", "9", "10", "100"]

?>

Pro Tips

  1. Cek kesamaan -> ===; cek urutan -> strcmp/<=>; cek mirip -> similar_text/levenshtein.
  2. strcmp hasilnya 0 = sama — jangan dibalik.
  3. natcasesort untuk data campuran teks+angka (nama file, produk, versi).
  4. version_compare untuk versi software — jangan pernah strcmp.
  5. htmlspecialchars($x, ENT_QUOTES, 'UTF-8') sebelum echo — kebiasaan yang menyelamatkan dari XSS.
  6. <=> (spaceship) sangat praktis sebagai callback usort.

Exercise

  1. Buat function untuk compare version strings (1.0 vs 1.1)
  2. Gunakan natural sort untuk filename list
  3. Kenapa htmlspecialchars() penting untuk keamanan?
  4. Tulis function cari_terdekat(string $kata, array $kandidat): string yang mengembalikan kandidat paling mirip menggunakan levenshtein.
  5. Urutkan array ["Buku 2", "Buku 10", "Buku 1", "Buku 21"] dengan natcasesort dan tampilkan hasilnya.
  6. Tampilkan komentar user berikut dengan aman di HTML: "<script>alert('hack')</script> Saya suka <b>PHP</b>!" — tunjukkan output yang aman.

Summary

KebutuhanAlatHasil
Sama/tidak==, ===, !=, !==boolean
Urutanstrcmp, strcasecmp, strncmp-1 / 0 / 1
Urutan ringkas<=> (spaceship)-1 / 0 / 1
Sortir naturalnatcasesort, natsortarray terurut
Versi softwareversion_compare-1 / 0 / 1
Kemiripansimilar_text (%), levenshtein (jarak)angka
Output amanhtmlspecialcharsstring ter-escape

Klik tombol ini setelah menyelesaikan materi

📝

Quiz Bab 7

Uji pemahamanmu tentang String Manipulation