You are using an outdated browser. For a faster, safer browsing experience, upgrade for free today.

Loading...

Blog

Zde najdete zajímavé články ze světa IT.
Chcete napsat článek? Zapojte se.

PHP je mrtvé. Ať žije PHP!!!

zpět na kategorii Mechaniky jazyka - Před rokem, Autor: Antonín Jehlář


Pořád slýcháte, jak je PHP mrtvý jazyk, jak je k ničemu a že v něm vznikají špatné aplikace? Tak si dnes ukážeme, jak to doopravdy je.



Už jste slyšeli, že PHP je mrtvé? A ptali jste se proč? Většina lidí ani neví, proč se to říká. Prostě říkají, co slyšeli od ostatních (#1)

Toto je první část série!!!

Určitě jsi slyšel, nebo četl, že PHP má spoustu nástrojů. Na každou věc, co by si mohl najít má nějaký. Ale že tyto nástroje jsou při podrobnějším pohledu nějak divné. Například, že kladivo má na obou stranách část pro vytahováíní hřebíků...

Double tail hammer PHP

S takovými nástroji se prý dá postavit velice hezký dům, ale když se na něj podíváte, tak je ve výsledku vzhůru nohama.

Upside down house PHP

Upozorňuji, že tohle bude opravdu dlouhé čtení, jelikož si v tomhle článku rozebereme dopodrobna rozdíly mezi PHP a ostaními hojně používanými jazyky.

Nebudeme dělat benchmarky. Těch je na netu plno. Ale rozhodně se podíváme na rozdíly zápisů běžných věcí v PHP a ostatních jazycích. Budu používat čisté PHP a čisté ostatní jazyky. Knihovna totiž může řešit všechny problémy, kromě performance. Tedy bych rád porovnal schopnosti jazyka jako takového.

Musím upozornit, že u některých jazyků ani nevím, jak daná věc funguje, ale příklady jsou napsány experty na daný programovací jazyk.

Jako hodnocení použiju to, na kolik řádků je kód zapsán a taktéž, jak moc přehledný je. Přehlednost je hodně subjektivní věc, jelikož kdo daný jazyk zná, tak se v něm orientuje rychleji, budu se tedy snažit ji hodnotit podle pohledu nováčka, který žádný jazyk nezná. Tím zajistím, že budou mít všechny jazyky stejnou šanci.

1. Callbacky

V této kapitole se podíváme na callbacky. Jde o základní součást každého jazyka, a je tedy třeba je porovnat, protože to může být jedna z nejvíce častých věcí, které budete muset ve svém kódu použít.

C++

#include <iostream>

using namespace std;

struct ComparisonOperator
{
    int operator()(int a, int b) const
    {
        return a - b;
    }
};

template<typename Callable>
void sort(int *toSort, int arrLen, const Callable & comparator)
{
    int tmp;
    for (int i = 0; i < arrLen - 1; i++) {
        for (int j = i + 1; j < arrLen; j++) {
            if (comparator(toSort[i], toSort[j]) > 0) {
                tmp = toSort[j];
                toSort[j] = toSort[i];
                toSort[i] = tmp;
            }
        }
    }
}

int main()
{
    int arrLen = 4;
    int arr[arrLen] = {5, 2, 8, 1};
    
    ComparisonOperator c;
    sort(arr, arrLen, c);
    
    for (int i = 0; i < arrLen; i++) {
        std::cout << arr[i];
        if (i != arrLen - 1) {
            std::cout << ", ";
        }
    }

    return 0;
}

Spustitelný kód

Jak vidíme, tak v C++ se toto provádí nemotorně s pomocí nějakých struktur a složitého předávání velikostí pole zvlášť.

Přehlednost: 3/10

Počet řádků: 44

2. C#

using System;

public class HelloWorld
{
    
    public static void Main(string[] args)
    {
        Sorter sorter = new Sorter();
        int[] numbers = { 5, 2, 8, 1 };
        Sorter.ComparisonDelegate del = new Sorter.ComparisonDelegate(ComparisonCallback);
        
        sorter.Sort(numbers, del);
        
        Console.WriteLine(string.Join(", ", numbers));
    }
    
    public static int ComparisonCallback(int x, int y)
    {
        return x - y;
    }
}

public class Sorter 
{
    public delegate int ComparisonDelegate(int x, int y);
    
    public void Sort(int[] array, ComparisonDelegate comparisonDelegate)
    {
        int n = array.Length;
        int temp;
        for (int i = 0; i < n - 1; i++)
        {
            for (int j = i + 1; j < n; j++)
            {
                if (comparisonDelegate(array[i], array[j]) > 0)
                {
                    temp = array[j];
                    array[j] = array[i];
                    array[i] = temp;
                }
            }
        }
    }
}

Vyzkoušet můžeš tady

Jak vidíme, tak v C# se toto provádí už o něco lépe. Potřeba jsou delegáti, kteří nahradili C++ struktury, stále ale má kód 44 řádků, i když přehlednost vzrostla. Nevýhoda je, že je potřeba znát delegáty a vědět co to je. Na druhou stranu delegáti zapříčiní, že bude funkce volána se správnými parametry. Ale ruku na srdce. Viděli jste někdy tak hloupého programátora, že by nevěděl, co do funkce posílá?

Přehlednost: 7/10

Počet řádků: 44

3. Java

import java.util.Arrays;

interface Comparator {
    
    Integer compare(Integer x, Integer y);
}

class ComparatorImpl implements Comparator {

    @Override
    public Integer compare(Integer x, Integer y){
        return x - y;
    }
}

class Sorter {

    public Integer[] sort(Integer[] arr, Comparator comparator){
        Integer len = arr.length;
        Integer tmp;
        for (Integer i = 0; i < len - 1; i++){
            for (Integer j = i + 1; j < len; j++){
                if (comparator.compare(arr[i], arr[j]) > 0){
                    tmp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = tmp;
                }
            }
        }
        
        return arr;
    }
}

class HelloWorld {
    
    public static void main(String[] args) {
        Comparator comparator = new ComparatorImpl();
        Sorter sorter = new Sorter();
        Integer[] arr = { 5, 2, 8, 1 };
        arr = sorter.sort(arr, comparator);
        
        System.out.println(Arrays.toString(arr));
    }
}

Vyzkoušet můžeš tady

Tady je jasně vidět, že Java, jako taková, callbacky nemá. Respektive má, ale ty jsou tzv. 'consumers' a nemohou vracet hodnotu. Klasické Callbacky Java simuluje pomocí interfaces (náhrada za delegáty v C#) a třídou implementující toto rozhraní. Tento přístup je nešikovný, protože vlastně ztrácíme flexibilitu nad voláním funkce a musíme s ní vždy předávat i kontext, což je celá třída, respektive její instance.

Přehlednost: 7/10

Počet řádků: 45

4. RUST

struct Sorter;

impl Sorter {
    fn sort<T>(&self, array: &mut [T], comparison_delegate: fn(&T, &T) -> i32) {
        let n = array.len();
        for i in 0..n - 1 {
            for j in i + 1..n {
                if comparison_delegate(&array[i], &array[j]) > 0 {
                    array.swap(i, j);
                }
            }
        }
    }
}

fn comparison_callback(x: &i32, y: &i32) -> i32 {
    x - y
}

fn main() {
    let mut sorter = Sorter;
    let mut numbers = vec![5, 2, 8, 1];
    let comparison_delegate: fn(&i32, &i32) -> i32 = comparison_callback;

    sorter.sort(&mut numbers, comparison_delegate);

    println!("{:?}", numbers);
}

Vyzkoušet můžeš tady

Jak je na první pohled vidět, RUST je kratší než ostatní kódy. A jak se říká, tak s kratším kódem přichází větší přehlednost. Bohužel ne však v případě RUSTu. Místo jednoduchého lidským jazykem čitelného kódu se RUST rozhodl jít cestou hieroglifů, na první pohled tedy vypadá hezky, ale tím, že používá zkratky, se z něj stává nečitelný balast pro toho, kdo mu nerozumí. Na tento kód jsem si musel zavolat pomocníka AI, jelikož jsem nenašel žádného experta, který by to byl takto pěkně schopen napsat sám. Přihlašte se tedy, pokud někdo tento kód umíte vylepšit.

Přehlednost: 2/10

Počet řádků: 28

5. JavaScript

let compare = function(x, y) {
    return x - y;
}

let Sorter = {
    sort: function (arr, comparator) {
        let len = arr.length;
        for (i = 0; i < len - 2; i++) {
            for (j = i + 1; j < len; j++) {
                if (comparator(arr[i], arr[j]) > 0) {
                    [arr[i], arr[j]] = [arr[j], arr[i]];
                }
            }
        }
    }
};

let arr = [5, 2, 8, 1];
Sorter.sort(arr, compare);
console.log(arr);

Vyzkoušet můžeš tady

JavaScript nám už posunul laťku trochu výše. Žádné zbytečné znaky, žádné nesrovnalosti, callback se rovnou přiřazuje do proměnné a hned se posílá tam, kde je třeba. Nevýhoda je, že si nemůžeme explicitně určit datové typy, a nebude nám IDE napovídat, takže lidé slabší mysli, kteří si nepamatují, co sami napsali, nebo jaké mají ve firmě a v týmu standardy se musejí spolehnout na komentáře popisující datové typy a návratové hodnoty. Výhoda ovšem je, že velice často je IDE schopné tyto datové typy samo doplnit a napovídat i bez jejich definice, tedy často ani nejsou potřeba. Taktéž se dá jednoduše číst a nejsou tam žádné speciální znaky jako v případě RUSTu. Taktéž si můžeme anonymní funkci rovnou uložit do proměnné a chovat se k ní jako k proměnné. To nám dává výhodu ve chvíli, kdy potřebujeme například vyměnit funkci, ale nechat stejný název.

Přehlednost: 9/10

Počet řádků: 20

6. Python

def compare(x, y):
    return x - y

class Sorter:
    @staticmethod
    def sort(arr, comparator):
        len_arr = len(arr)
        for i in range(len_arr - 1):
            for j in range(i + 1, len_arr):
                if comparator(arr[i], arr[j]) > 0:
                    arr[i], arr[j] = arr[j], arr[i]

arr = [5, 2, 8, 1]
Sorter.sort(arr, compare)
print(arr)

Vyzkoušet můžeš tady

Zde to funguje obdobně jako v JavaScriptu. Navíc zde ale nemusejí být závorky, tedy je kód ještě kratší. Jako nevýhodu vidím, že je nutno použít @staticmethod, pokud nechceme tvořit instanci. V JS je po napsání objektu automaticky vytvořena jeho instance a vložena do dané proměnné, což eliminuje definici statických funkcí. Ještě bych chtěl vyzdvihnout, že díky Golfingu se v Pythonu dá většina věcí zapsat velice efektivně z pohledu počtu řádků. Takový kód však opět již může být nepřehledný, protože není na první pohled zřejmé, co se děje. Nicméně to, že chybí závorky, se může občas zdát matoucí, proto Python přišel o 1 bod.

Přehlednost: 8/10

Počet řádků: 15

7. PHP

<?php
$compare = function (int $x, int $y): int {
    return $x - $y;
};

class Sorter {
    public static function sort(array &$arr, \Closure $comparator): void {
        $len = count($arr);
        for ($i = 0; $i < $len - 1; $i++) {
            for ($j = $i + 1; $j < $len; $j++) {
                if ($comparator($arr[$i], $arr[$j]) > 0) {
                    [$arr[$i], $arr[$j]] = [$arr[$j], $arr[$i]];
                }
            }
        }
    }
}

$arr = [5, 2, 8, 1];
Sorter::sort($arr, $compare);
echo(implode(', ', $arr));

Vyzkoušet můžeš tady

Jak vidíme, kód je velice podobný JavaScriptu. Navíc tu jsou jen dolary a možnost vytvořit plnohodnotný objekt. Od krátkosti Pythonu se liší jen závorkami, což je v pořádku, protože to nemá příliš velký vliv na čitelnost, kromě toho, že závorky pomáhají lépe udržovat kontext, a v neposlední řadě má PHP navíc možnost, oproti JavaScriptu, si definovat datové typy proměnných. Pole je sice stále jen pole, ale detailnější definici můžeme opět napsat do komentáře v případě, že budeme mít za kolegu někoho, kdo se v kódu bez přesných definic nevyzná.

Přehlednost: 9/10

Počet řádků: 21

Závěr

Nejlépe si na počet řádků vedlo PHP, JavaScript a Python. Python si vedl nejlépe jen proto, že nemá závorky a tedy u něj zrovna počet řádků nehraje takovou roli, protože ukončující řádky se závorkou jsou vlastně jen prázdné řádky a nemají rozhodující vliv na čitelnost.

O první místo v přehlednosti se opět dělí PHP a JavaScript, jelikož jsou podobné běžné řeči a kód je krátký, bez spousty speciálních znaků a tedy je rychleji pochopitelný.

Vím, že jsou v různých jazycích různé vychytávky, jak kterou věc zapsat, ale chtěl jsem demonstrovat hlavně, jakým způsobem se s callbacky pracuje, jak se volají atd. Zkrátit tedy funkci na jeden řádek jen proto, že to sort umožňuje by bylo kontraproduktivní.

To je pro tento díl vše. Pokud něco nechápeš, tak mi napiš.

Tak užívej a já jdu sladit včelám med.