Saturday, July 13, 2019

PHP 7.4.x, dan Kebiasaan-Kebiasaan yang Perlu Anda Ubah

Logo PHP
Logo PHP.

Selalu ada hal-hal yang menarik untuk diceritakan dari sejarah bahasa pemrograman, salah satunya adalah bahasa pemrograman PHP yang hingga saat ini telah digunakan oleh 79% dari situs web di seluruh dunia. Terdapat berbagai kritik negatif mengenai keberadaannya, beberapa di antaranya adalah karena inkonsistensi hasil yang diberikan ketika sebuah data dibandingkan atau disatukan dengan data yang lain, juga mengenai keputusan penamaan fungsi yang sangat tidak terpola. Tapi di luar dari semua itu, Rasmus Lerdorf sendiri mengatakan bahwa beliau tidak pernah merencanakan PHP. Semuanya terjadi begitu saja.

“Well, I didn’t plan PHP. I think in terms of solving problems, not in terms of software projects. I actually hate programming, but I love solving problems.”

Dengan proyek pengembangan perangkat lunak yang tidak terencana seperti itu tentu saja akan membawa kita pada kebiasaan-kebiasaan buruk yang terbentuk bukan karena kita yang tidak disiplin akan tetapi karena tidak adanya aturan yang jelas mengenai kaidah-kaidah pemrograman. Tidak ada aturan yang pasti apakah 123 == '123x' akan memberikan hasil yang sama dengan '123' == '123x'. Bahasa sederhananya: PHP itu terlalu bebas!

Sejak rilis PHP 7.0.0 hingga sekarang, telah begitu banyak perubahan yang terjadi di dalam ekosistem PHP. Dan Saya akui kondisinya makin membaik. Kecepatan eksekusinya meningkat drastis. Masih belum bisa dikatakan sempurna memang, namun sampai sekarang fitur-fitur baru dan perbaikan-perbaikan masalah di sana-sini masih terus dilakukan. Melalui artikel ini, Saya ingin membahas beberapa hal terkait dengan cara Anda menulis kode PHP di masa lalu. Karena PHP versi 7.0.0 sudah tidak sama lagi dengan PHP versi yang dulu. Meskipun kode lama Anda masih dapat bekerja di versi PHP yang baru, akan tetapi tidak ada salahnya jika Anda mengikuti beberapa saran Saya untuk mulai membiasakan diri menulis kode PHP dengan lebih baik lagi karena jujur saja Saya tidak suka membaca kode-kode PHP yang kalian tulis!

Gunakan Sintaks Jajaran Pendek

Fitur ini sebenarnya sudah ada sejak PHP 5.4.0 bersamaan dengan hadirnya fitur Trait. Selain dapat meringkas kode dan memperkecil ukuran berkas, sintaks ini juga akan sangat serasi ketika dipadukan dengan perintah peletakan dan pengambilan data jajaran:

$array = ['A', 'B', 0, true];

$array[0] = 'Z';

echo $array[0];

Nilai Alternatif

Dahulu kita menggunakan cara-cara seperti ini untuk menentukan nilai alternatif ketika data yang diminta tidak ada:

$var = isset($array['var']) ? $array['var'] : 1;
$var = array_key_exists('var', $array) ? $array['var'] : 1;

Namun sejak kemunculan operator penggabungan null pada PHP 7.0.0, sekarang kita bisa dengan sangat mudah membuat deretan nilai alternatif tanpa harus melalui perintah isset berkali-kali:

$var = $array['var'] ?? 1;
$var = $foo['var'] ?? $bar['var'] ?? $baz ?? 1;

Argumen Fungsi

func_get_arg(), func_get_args(), dan func_num_args() adalah fungsi-fungsi yang paling sering kita gunakan untuk mendapatkan data argumen dari sebuah fungsi. Cara penggunaannya adalah seperti berikut:

function image($image, $x = null, $y = null, $w = null, $h = null) {
    // `image('.\path\to\image.jpg', $w, $h)`
    if (func_num_args() < 4) {
        $w = $x;
        $h = $y;
        return resize($image, $w, $h);
    }
    // `image('.\path\to\image.jpg', $x, $y, $w, $h)`
    return crop($image, $x, $y, $w, $h);
}

Perhitungan-perhitungan argumen fungsi seperti ini biasanya dibuat untuk mempermudah pengguna dalam menggunakan fungsi utama, yaitu dengan cara mengizinkan mereka untuk melompati beberapa variabel yang sifatnya opsional. Contoh lain dapat Anda temukan juga pada cara kerja fungsi substr().

Beberapa orang menganggap fitur-fitur tersebut (fungsi func_get_arg(), func_get_args(), dan func_num_args()) sebagai fitur yang buruk dan tidak logis karena fungsi tidak seharusnya memiliki akses kepada pengurai sintaks PHP itu sendiri. Kelemahan ini juga tampak pada fungsi get_called_class() dan get_parent_class(), yang sekarang sudah mengalami perkembangan yang lebih baik dengan hadirnya konstanta *::class pada PHP 5.5, sehingga kita tidak perlu lagi menggunakan fitur-fitur tersebut.

Untuk membuat peraturan kondisi berdasarkan argumen fungsi menjadi tampak lebih nyaman untuk dibaca, kita bisa menggunakan fitur pembongkar argumen yang hadir pada PHP 5.6:

function image(...$args) {
    // `image('.\path\to\image.jpg', $w, $h)`
    if (count($args) < 4) {
        return resize(...$args);
    }
    // `image('.\path\to\image.jpg', $x, $y, $w, $h)`
    return crop(...$args);
}

Dan untuk mendapatkan nama kelas yang sedang dieksekusi, kita bisa menggunakan konstanta *::class atau __CLASS__ seperti ini:

class Foo {

    public function getClassName1() {
        return static::class;
    }

    public function getClassName2() {
        return __CLASS__;
    }

}

Oya! Sebagai informasi tambahan saja, pada JavaScript kita bisa menuliskan arguments begitu saja untuk mendapatkan daftar argumen fungsi yang ada. Jadi, di sini arguments berlaku sebagai token keyword yang bekerja sebagaimana token if, var, function, dan kawan-kawan:

function image() {
    if (arguments.length < 4) {
        return resize.apply({}, arguments);
    }
    return crop.apply({}, arguments);
}

Fitur Pembongkaran dan Pengepakan Argumen

Kasus ini hampir sama dengan kasus sebelumnya, hanya saja di sini Saya lebih cenderung kepada fitur sebaliknya yaitu fitur pengepakan argumen. Dengan fitur ini, kita tidak perlu lagi menggunakan fungsi-fungsi yang biasanya memiliki pola penamaan *_array seperti call_user_func_array() dan preg_replace_callback_array(). Karena kita bisa meletakkan data jajaran sebagai deret argumen fungsi dengan cara seperti ini:

$args = ['A', 0, true];

call_user_func('foo', ...$args); // Sama dengan `call_user_func('foo', $args[0], $args[1], $args[2])`

Operator Sebar pada Jajaran

Fitur ini dapat digunakan untuk mengeliminasi fungsi array_merge(). Cara penggunaannya adalah seperti ini:

$array = ['A', 'B', 'C'];

return [0, 1, 2, ...$array]; // `[0, 1, 2, 'A', 'B', 'C']`

Selain dari itu, fitur ini juga memiliki satu kelebihan lagi yaitu dapat diletakkan di antara data jajaran. Jadi tidak harus berada di akhir jajaran:

return [0, 1, 2, ...$array, true]; // `[0, 1, 2, 'A', 'B', 'C', true]`

Perintah-perintah yang kompatibel untuk digunakan pada PHP dengan versi yang lebih lama adalah sebagai berikut:

return array_merge([0, 1, 2], $array);

return [0, 1, 2] + $array;
$a = [0, 1, 2, true];
$b = array_pop($a);

return array_merge($a, $array, [$b]);

Deklarasi Tipe pada Argumen dan Pengembalian Fungsi

Dengan menggunakan fitur ini, selain dapat menampilkan pesan kesalahan ketika masukan data yang diberikan ke dalam argumen fungsi tidak sesuai dengan jenis data yang diinginkan, fitur ini juga dapat mempermudah pembaca kode sumber untuk memahami apa maksud dan penggunaan fungsi tersebut tanpa harus membaca dokumentasi secara lengkap:

interface Get {
    public function chunk(array $data, int $i): array {}
    public function files(string $path, string $x): Pages {}
    public function __toString(): string {}
}

Pada bagian __toString() sebenarnya agak berlebihan. Kode di atas hanya sebagai contoh saja.

Konversi Penamaan

Ada baiknya untuk mengikuti kaidah-kaidah tertentu dalam menuliskan nama konstanta, variabel, kelas dan fungsi seperti bagaimana cara memisahkan kata-kata pada deret nama, apakah dengan membedakan besar dan kecilnya huruf, atau dengan menggunakan karakter garis bawah seperti ini:

$foo;
$foobar;
$foobarbaz;
$foo;
$fooBar;
$fooBarBaz;
$Foo;
$FooBar;
$FooBarBaz;
$foo;
$foo_bar;
$foo_bar_baz;

Kita juga perlu menentukan bagaimana urutan prioritas pada masing-masing sub-nama. Apakah ingin mengaturnya dari kiri ke kanan untuk menciptakan kesan hirarki, atau dengan cara mengaturnya dari kanan ke kiri untuk menciptakan kesan kalimat yang dapat dibaca secara alami:

function button(): string {}
function button_primary(): string {}
function button_primary_large(): string {}
function button(): string {}
function buttonPrimary(): string {}
function buttonPrimaryLarge(): string {}
namespace {
    function button(): string {}
}

namespace button {
    function primary(): string {}
}

namespace button\primary {
    function large(): string {}
}
function button(): string {}
function primaryButton(): string {}
function largePrimaryButton(): string {}

Pastikan untuk mengikuti pola-pola tersebut secara konsisten hingga proyek Anda selesai sehingga kode Anda akan lebih mudah untuk diurus di kemudian hari. Pola yang konsisten juga dapat mempermudah Anda dan orang lain untuk melakukan pencarian nama konstanta, variabel, kelas dan fungsi tertentu melalui perintah Find & Replace karena konsep penamaan yang sudah terpola.

Hemat dalam Menggunakan Variabel

Dahulu kita tidak bisa mengambil satu item dari string yang dipisahkan oleh fungsi explode() secara langsung karena cara kerja pengurai token PHP yang masih sangat terbatas. Jadilah kita menggunakan ekstra variabel untuk mengatasi masalah tersebut:

$tags = explode(', ', 'Foo, Bar, Baz');

echo $tags[0];

Tapi masalah tersebut sudah berhasil diatasi sejak PHP versi 5.4, sehingga kita bisa mengambil item tertentu secara langsung dari pengembalian fungsi explode() seperti ini:

echo explode(', ', 'Foo, Bar, Baz')[0];

Ringkas juga pemanggilan metode-metode kelas atau data-data dari pengembalian fungsi jika memang memungkinkan dan tidak merusak keterbacaan:

echo (new Page('.\path\to\page.md'))->get('title');
echo q2o('?a=b&c=d&e=f')['c'] ?? false;

Keterbacaan PHP di dalam Berkas HTML

Usahakan untuk menghindari kebiasaan mencampurkan antara kode PHP sebagai program dengan kode PHP sebagai bagian dari kode HTML seperti ini:

<h2>
  <?php if ($page->link) { ?>
  <a href="<?php echo $page->link; ?>" target="_blank">
    <?php echo $page->title; ?>
  </a>
  <?php } else if ($page->url) { ?>
  <a href="<?php echo $page->url; ?>">
    <?php echo $page->title; ?>
  </a>
  <?php } else { ?>
  <span>
    <?php echo $page->title; ?>
  </span>
  <?php } ?>
</h2>

PHP pada dasarnya memiliki peran ganda, selain sebagai scripting language juga sebagai templating language, yang berarti bahwa kode PHP dapat disatukan dengan kode HTML. Jika yang ingin Anda tuliskan adalah kode untuk menampilkan data pada HTML, maka sintaks alternatif berikut ini akan lebih nyaman untuk dibaca, terutama oleh orang-orang yang ingin membuka berkas tersebut melalui editor kode berwarna:

<h2>
  <?php if ($page->link): ?>
  <a href="<?php echo $page->link; ?>" target="_blank">
    <?php echo $page->title; ?>
  </a>
  <?php elseif ($page->url): ?>
  <a href="<?php echo $page->url; ?>">
    <?php echo $page->title; ?>
  </a>
  <?php else: ?>
  <span>
    <?php echo $page->title; ?>
  </span>
  <?php endif; ?>
</h2>

Jangan juga mencampurkan kode PHP sebagai program dengan kode HTML mentah seperti ini, ini sangat kacau!

<?php

class Article {

    public function getHTML(string $source) {
        $data = fetch($source)->then(function($response) {
            return $response->json;
        })->then(function($json) {

?>
<article>
<h2><?php echo $json->title; ?></h2>
<div><?php echo $json->content; ?></div>
</article>
<?php

        })->catch(function() {
?>
<article>
<h2>Error</h2>
<div>Not found.</div>
</article>
<?php

        });
    }

}

Coba gunakan echo, atau return sebagai alternatif yang lebih baik. Atau pelajari konsep MVC.

Jangan Takut Menggunakan “Magic Methods”

Metode ajaib atau magic method dalam PHP dikenal sebagai metode yang berpotensi memperlambat proses eksekusi program PHP Anda karena dalam satu kali pemanggilan metode kelas yang dilengkapi dengan metode-metode ajaib, sebuah kelas perlu untuk mencari metode yang dimaksud terlebih dahulu untuk dieksekusi sebelum pada akhirnya kelas tersebut mengeksekusi metode ajaib yang diberikan ketika metode yang dimaksud ternyata tidak ditemukan. Tapi sekarang ini arsitektur PHP sudah makin berkembang menjadi lebih baik lagi termasuk juga dari segi kecepatannya. Satu-satunya kendala mengapa PHP tidak bisa secepat bahasa-bahasa pemrograman lain adalah karena kode PHP dibaca oleh mesin secara langsung, bukannya dikompil terlebih dahulu sebelum dibaca oleh mesin. Saya sudah menggunakan metode ajaib ini pada Mecha sejak versi 2.0.0 dan justru terdapat banyak manfaat yang Saya peroleh dari fitur yang hina ini. Salah satu manfaat besar yang Saya rasakan adalah Saya jadi bisa lebih hemat dalam menuliskan metode kelas. Tanpa metode ajaib, mungkin Saya perlu membuat kelas dengan metode-metode yang tak terhitung jumlahnya seperti ini:

<?php

class Page {
    protected $data = [];
    public function __construct(array $data) {
        $this->data = $data;
    }
    public function title() {
        return $this->data['title'] ?? null;
    }
    public function description() {
        return $this->data['description'] ?? null;
    }
    public function content() {
        return $this->data['content'] ?? null;
    }
    public function tags() {
        return $this->data['tags'] ?? null;
    }
    // …
}

Dengan metode ajaib, Saya hanya perlu fokus pada data-data yang masuk ke instansi kelas tersebut saja:

<?php

class Page {
    protected $data = [];
    public function __call(string $key, array $lot = []) {
        return $this->data[$key] ?? null;
    }
    public function __construct(array $data) {
        $this->data = $data;
    }
}

Setiap orang punya pendapat dan idealisme masing-masing, dan kebetulan Saya adalah salah satu orang yang mendapatkan keuntungan dari fitur tersebut. Sehingga Saya hanya bisa menyarankan Anda untuk berpikir lebih terbuka kepada keputusan-keputusan yang telah diambil oleh para pengembang. Dan sekedar informasi tambahan saja, __construct() dan __toString() pada PHP juga termasuk metode ajaib. Dan jika Anda bisa menerima kedua hal tersebut, kenapa Anda tidak bisa mencoba untuk menerima mereka juga?

Dan sebagai informasi tambahan juga, dalam JavaScript terdapat metode sejenis bernama constructor() dan toString(), serta kelas Proxy untuk memberikan efek yang sama. Python juga punya __init__() dan __str__().

Lain-Lain

IIFE (Immediately Invoked Function Expression)

Dahulu kita memerlukan call_user_func() untuk mengeksekusi fungsi anonim:

call_user_func(function($foo, $bar, $baz) {
    // Definisikan variabel pribadi di sini…
}, 'A', 0, true);

Sekarang kita bisa menggunakan gaya IIFE seperti pada JavaScript:

(function($foo, $bar, $baz) {
    // Definisikan variabel pribadi di sini…
})('A', 0, true);

Alternatif if..elseif..else dan switch..case..default

Para pengguna PHP pada umumnya akan menggunakan cara ini:

if ($var === 'true') {
    $value = true;
} else if ($var === 'false') {
    $value = false;
} else {
    $value = null; // Bawaan
}

echo $value;
switch ($var) {
    case 'true':
        $value = true;
        break;
    case 'false':
        $value = false;
        break;
    default:
        $value = null; // Bawaan
}

echo $value;

Tapi belakangan ini Saya lebih suka menggunakan cara seperti berikut:

$value = ([
    'true' => true,
    'false' => false
])[$var] ?? null;

echo $value;

Labels: ,

3 Comments:

At Sunday, July 28, 2019 at 9:57:00 PM GMT+7, Blogger sufyan Yaan said...

Lebih gampang belajar Php-an (pemberi harapan palsu) he he he...anyway nice info, gan

 
At Monday, July 29, 2019 at 10:13:00 PM GMT+7, Blogger Rohman said...

mau nanya apakah mencapur html dan php itu juga mempengaruhi kecepatan atau mempengaruhi proses sistem.

 
At Tuesday, July 30, 2019 at 7:04:00 PM GMT+7, Blogger Taufik Nurrohman said...

Intinya semakin sedikit kode PHP di dalam HTML akan semakin baik, karena akan mengurangi beban peladen web. Tapi jumlah tidak selalu menentukan performa. Beban perintah di dalam kode PHP juga menentukan:

while (1) echo 1;

Coba tambahkan perintah di atas ke dalam berkas PHP.

 

Post a Comment

<< Home