Di bawah semua angka yang kita olah, komputer hanya menyimpan deretan bit: nilai 0 dan 1. Operator bitwise memungkinkan program menyentuh lapisan tersebut secara langsung — menguji, menyalakan, dan mematikan bit individual. Kebutuhannya nyata di dunia profesional: kumpulan izin akses yang hemat memori, pemrosesan warna pada gambar, protokol jaringan, hingga kriptografi. Pada chapter ini kita akan mempelajari enam operator bitwise PHP, perilakunya pada bilangan 64-bit, dan pola bitmask yang menjadi penggunaannya paling umum sehari-hari.

Sedikit tentang Biner #

Sebelum menyentuh operatornya, kita segarkan cara membaca bilangan biner. Integer PHP pada lingkungan 64-bit tersimpan dalam 64 bit; bilangan 5 tersimpan sebagai 101, yaitu 1×4 + 0×2 + 1×1. PHP punya tiga format literal untuk menulis bilangan berbasis lain: 0b untuk biner, 0x untuk heksadesimal, dan 0o untuk oktal — semuanya menghasilkan integer biasa:

php
<?php
var_dump(0b1011);  // biner: 8 + 2 + 1
var_dump(0xFF);    // heksadesimal: 15*16 + 15
var_dump(0o17);    // oktal: 8 + 7
var_dump(PHP_INT_SIZE); // ukuran integer dalam byte

Output yang Dihasilkan:

text
int(11)
int(255)
int(15)
int(8)

Ketiga literal di atas menghasilkan integer 11, 255, dan 15 — format penulisan berbeda, nilai akhirnya sama. Konstanta PHP_INT_SIZE bernilai 8 byte, artinya integer PHP di lingkungan ini selebar 64 bit. Untuk menampilkan bentuk biner sebuah angka, fungsi printf() dengan format %b atau decbin() siap membantu saat kita menelusuri contoh.

Daftar Operator Bitwise #

OperatorNamaContohHasil
&AND5 & 31
|OR5 | 37
^XOR5 ^ 36
~NOT~5-6
<<Shift kiri5 << 220
>>Shift kanan16 >> 24

Operator &, |, dan ^ membandingkan kedua operan bit demi bit; operator ~ membalik seluruh bit satu operan; kedua operator shift menggeser bit ke kiri atau kanan sejauh posisi yang ditentukan.

AND, OR, XOR, dan NOT #

Mari kita bedah tiga operator pertama dengan operan 5 (0101) dan 3 (0011), ditampilkan berdampingan dalam biner:

php
<?php
printf("5     = %04b\n", 5);
printf("3     = %04b\n", 3);
printf("5 & 3 = %04b (%d)\n", 5 & 3, 5 & 3);
printf("5 | 3 = %04b (%d)\n", 5 | 3, 5 | 3);
printf("5 ^ 3 = %04b (%d)\n", 5 ^ 3, 5 ^ 3);

Output yang Dihasilkan:

text
5     = 0101
3     = 0011
5 & 3 = 0001 (1)
5 | 3 = 0111 (7)
5 ^ 3 = 0110 (6)

Operator & menghasilkan bit 1 hanya pada posisi yang 1 di kedua operan: dari 0101 dan 0011, hanya bit paling kanan yang sama-sama 1, hasilnya 0001 (angka 1). Operator | menghasilkan 1 bila salah satu operan bernilai 1, sehingga 0101 dan 0011 menghasilkan 0111 (7). Operator ^ menghasilkan 1 hanya pada posisi yang berbeda antara kedua operan — 0110 (6). Ketiganya identik dengan operator logika &&, ||, dan xor dari chapter sebelumnya, hanya saja bekerja per bit, bukan per nilai boolean.

Operator ~ membalik semua bit operan tunggalnya dan hasilnya mengejutkan pemula: ~5 adalah -6, bukan 2. Penyebabnya adalah representasi two’s complement yang dipakai untuk bilangan negatif — bit paling kiri (paling signifikan) menentukan tanda, dan membalik semua bit menggeser nilai ke wilayah negatif. Hubungannya rapi: ~$n selalu sama dengan -$n - 1:

php
<?php
var_dump(~5, -5 - 1);
var_dump(~0, -0 - 1);
var_dump(~(-1));

Output yang Dihasilkan:

text
int(-6)
int(-6)
int(-1)
int(-1)
int(0)

Shift Kiri dan Kanan #

Operator shift menggeser seluruh bit sejauh posisi tertentu. Menggeser satu kali ke kiri (<< 1) sama dengan mengalikan dua; menggeser ke kanan (>> 1) sama dengan membagi dua lalu membuang sisanya. Menggeser sejauh $n berarti mengalikan atau membagi dengan 2 ** $n:

php
<?php
var_dump(1 << 3);   // 1 * 2^3
var_dump(5 << 2);   // 5 * 2^2
var_dump(16 >> 2);  // 16 / 2^2
var_dump(7 >> 1);   // 7 / 2 dibuang sisanya
var_dump(-8 >> 1);  // shift kanan menjaga tanda
var_dump(-1 >> 1);  // bit tanda tetap terisi 1

Output yang Dihasilkan:

text
int(8)
int(20)
int(4)
int(3)
int(-4)
int(-1)

Ekspresi 7 >> 1 menghasilkan 3 — hasil 3.5 dipotong menjadi integer karena bit yang tergeser keluar hilang begitu saja. Perhatikan dua baris terakhir: pada bilangan negatif, PHP memakai arithmetic shift yang menyalin bit tanda, sehingga -8 >> 1 menghasilkan -4 dan -1 >> 1 tetap -1 (semua bit 1 digeser tetap menghasilkan semua bit 1). Walaupun << secara historis dipakai sebagai “perkalian cepat”, pada PHP modern selisih kecepatannya bisa diabaikan — gunakan shift ketika memang sedang bekerja di ranah bit, dan tulis perkalian biasa untuk matematika biasa.

Batas 64-Bit #

Karena integer hanya selebar 64 bit, menggeser terlalu jauh membuat bit “jatuh” keluar dari wadahnya. Bit yang digeser melewati posisi 63 hilang, dan bit paling kiri berperan sebagai tanda. Hasilnya bisa aneh bila tidak diantisipasi:

php
<?php
var_dump(1 << 62);
var_dump(1 << 63);       // bit tanda ikut menyala
var_dump(PHP_INT_MIN);   // bandingkan dengan 1 << 63
var_dump(1 << 64);       // semua bit tergeser keluar

Output yang Dihasilkan:

text
int(4611686018427387904)
int(-9223372036854775808)
int(-9223372036854775808)
int(0)

Menggeser 1 ke posisi 63 menyalakan bit tanda sehingga hasilnya bukan bilangan positif besar, melainkan PHP_INT_MIN (-9223372036854775808). Menggeser sejauh 64 atau lebih membuat semua bit bernilai 1 terdorong keluar sehingga hasilnya 0. Satu lagi pagar pengaman: menggeser dengan jumlah negatif (1 << -1) melempar ArithmeticError: Bit shift by negative number dan menghentikan program bila tidak ditangkap.

Praktik: Bitmask untuk Kumpulan Izin #

Penggunaan bitwise yang paling sering dijumpai aplikasi sehari-hari adalah bitmask: memampatkan banyak pilihan “ya/tidak” menjadi satu integer dengan setiap bit mewakili satu opsi. Pola baku untuk memberi nama tiap bit adalah konstanta berurutan 1, 2, 4, 8, dan seterusnya — satu bit menyala per konstanta:

php
<?php
const IZIN_BACA  = 1;  // 0b001
const IZIN_TULIS = 2;  // 0b010
const IZIN_HAPUS = 4;  // 0b100

$peranEditor = IZIN_BACA | IZIN_TULIS;
var_dump($peranEditor);

var_dump(($peranEditor & IZIN_BACA) === IZIN_BACA);
var_dump(($peranEditor & IZIN_HAPUS) === IZIN_HAPUS);

$peranEditor |= IZIN_HAPUS;   // menambah izin
var_dump($peranEditor);

$peranEditor &= ~IZIN_TULIS;  // mencabut izin
var_dump($peranEditor);

$peranEditor ^= IZIN_BACA;    // mengganti status (togel)
var_dump($peranEditor);

Output yang Dihasilkan:

text
int(3)
bool(true)
bool(false)
int(7)
int(5)
int(4)

Mari kita bedah tiap baris. Ekspresi IZIN_BACA | IZIN_TULIS menggabungkan dua izin menjadi 3 (0b011). Pemeriksaan ($peranEditor & IZIN_BACA) === IZIN_BACA menguji apakah bit izin baca menyala: operator & menyaring hanya bit-bit yang ditanyakan, lalu hasil dibandingkan ketat dengan konstantanya. Operator gabungan |= menyalakan bit baru tanpa mengusik bit lain; &= ~IZIN_TULIS mematikan bit tulis dengan cara AND terhadap kebalikan konstanta; ^= menyalakan bit yang mati dan mematikan bit yang hidup — persis saklar togel. Dengan tiga operator gabungan ini, seluruh operasi himpunan (tambah, hapus, togel, uji) selesai tanpa array maupun kondisi berantai.

Berkas contoh.php pada bagian bawah halaman merangkum seluruh contoh chapter ini dalam satu program yang bisa dijalankan langsung.

Referensi #

Ringkasan #

Operator bitwise &, |, ^, ~, <<, >> mengolah integer bit demi bit: AND menyaring, OR menggabungkan, XOR mencari perbedaan, NOT membalik (ingat ~$n = -$n - 1), dan shift menggeser dengan batas 64-bit — 1 << 63 menyalakan bit tanda menjadi PHP_INT_MIN, sedangkan shift negatif melempar ArithmeticError. Pola bitmask memampatkan kumpulan opsi boolean ke satu integer dengan operasi |=, &= ~, dan ^=. Dari ranah bit kita naik ke operator yang lebih modern dan khas PHP — dimulai dengan null coalescing operator pada chapter berikutnya.

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

contoh.php

Unduh berkas
php
<?php
// contoh.php — rangkuman Operator Bitwise
// Jalankan dengan: php contoh.php

echo "== Literal bilangan berbasis lain ==\n";
var_dump(0b1011, 0xFF, 0o17, PHP_INT_SIZE);

echo "\n== AND, OR, XOR, NOT ==\n";
printf("5     = %04b\n", 5);
printf("3     = %04b\n", 3);
printf("5 & 3 = %04b (%d)\n", 5 & 3, 5 & 3);
printf("5 | 3 = %04b (%d)\n", 5 | 3, 5 | 3);
printf("5 ^ 3 = %04b (%d)\n", 5 ^ 3, 5 ^ 3);

var_dump(~5, -5 - 1);   // ~n == -n - 1
var_dump(~0, ~(-1));

echo "\n== Shift kiri dan kanan ==\n";
var_dump(1 << 3, 5 << 2, 16 >> 2, 7 >> 1);
var_dump(-8 >> 1, -1 >> 1); // arithmetic shift menjaga tanda

echo "\n== Batas 64-bit ==\n";
var_dump(1 << 62);
var_dump(1 << 63);      // sama dengan PHP_INT_MIN
var_dump(PHP_INT_MIN);
var_dump(1 << 64);      // semua bit tergeser keluar

echo "\n== Bitmask izin ==\n";
const IZIN_BACA  = 1;  // 0b001
const IZIN_TULIS = 2;  // 0b010
const IZIN_HAPUS = 4;  // 0b100

$peranEditor = IZIN_BACA | IZIN_TULIS;
var_dump($peranEditor);

var_dump(($peranEditor & IZIN_BACA) === IZIN_BACA);
var_dump(($peranEditor & IZIN_HAPUS) === IZIN_HAPUS);

$peranEditor |= IZIN_HAPUS;   // menambah izin
var_dump($peranEditor);

$peranEditor &= ~IZIN_TULIS;  // mencabut izin
var_dump($peranEditor);

$peranEditor ^= IZIN_BACA;    // mengganti status (togel)
var_dump($peranEditor);