Na navigaci | Klávesové zkratky

Translate to English… Ins Deutsche übersetzen…

Composer: jak na různé varianty instalace

Composer, nejdůležitější nástroj pro PHP vývojáře, umožňuje 3 způsoby, jak instalovat balíčky:

  • lokální composer require vendor/name
  • globální composer global require vendor/name
  • jako projekt composer create-project vendor/name

Lokálně

Lokální instalace se používá nejčastěji. Mám projekt, ve kterém chci třeba použít Tracy, tak v kořenovém adresáři projektu zadám:

composer require tracy/tracy

a Composer zaktualizuje (nebo vytvoří) soubor composer.json a stáhne Tracy do podsložky vendor. Zároveň vygeneruje autoloader, takže v kódu jej stačí inkludovat a můžu rovnou Tracy použít:

require __DIR__ . '/vendor/autoload.php';
Tracy\Debugger::enable();

Nástroje

Diametrálně odlišná situace nastává tehdy, pokud místo knihovny, jejíž třídy ve svém projektu používám, instaluji nástroj, který jen spouštím z příkazové řádky.

Příkladem může být třeba ApiGen pro generování přehledných API dokumentací. V takovém případě se použije třetí způsob:

composer create-project apigen/apigen

Composer vytvoří novou složku (a tedy i nový projekt) apigen a do ní stáhne celý nástroj a nainstaluje jeho závislosti.

Bude mít vlastní composer.json a vlastní podsložku vendor.

Tímto způsobem se instaluje i třeba Nette Sandbox nebo CodeChecker. Nikoliv však testovací nástroje jako je Nette Tester nebo PHPUnit, protože jejich třídy naopak v testech používáme, voláme Tester\Assert::same() nebo dědíme od PHPUnit_Framework_TestCase.

Bohužel Composer umožňuje instalovat nástroje jako je ApiGen i pomocí composer require a nevypíše ani žádné varování.

Což je totéž, jako když donutíte dva vývojáře, kteří se ani neznají a kteří pracují na úplně jiném projektu, aby sdíleli společnou složku vendor. Na to se dá říci:

  • Proboha proč by to měli dělat?
  • Vždyť to přece nemůže fungovat!

Ano, není žádný rozumný důvod to dělat, nic to nepřinese, naopak to přestane fungovat v momentě, kdy dojde ke kolizi používaných knihoven. Je to jen otázka času, stavění domečku z karet, který se dřív nebo později sesype. Jeden projekt bude vyžadovat knihovnu XY ve verzi 1.0, druhý ve verzi 2.0 a v tu chvíli to přestane fungovat.

Globálně

Rozdíl mezi variantou 1) a 2), tj. mezi composer require a composer global require, je pak v tom, že nepůjde o dva cizí vývojáře, ale o deset cizích vývojářů a deset nesouvisejících projektů. Tedy je to nesmysl na druhou.

Totiž composer global je špatné řešení úplně vždy, neexistuje use case, kdy by bylo vhodné jej použít. Byl jsem zvědavý, jak se mohlo něco takového dostat do Composeru, a vypadá to, nepletu-li se, že tento nesmysl přidal můj oblíbený troll :-)

(Jako ukázku si můžete globálně nainstalovat dg/composer-global-is-useless. Poté už nepůjde globálně nainstalovat ani PHPUnit.).

Rekapitulace

  • composer require vendor/name pokud chcete používat třídy knihovny
  • composer global require vendor/name nikdy!
  • composer create-project vendor/name pro nástroje volané jen z příkazové řádky

Poznámka: npm používá odlišnou filosofii danou možnostmi JavaScriptu a každou knihovnu instaluje jako „samostatný projekt“, s vlastním adresářem vendor (resp. node_modules). Ke konfliktu verzí tak dojít nemůže. V případě npm naopak platí, že globální instalace nástrojů, jako je například LESS CSS, jsou velmi užitečná a příjemná věc.

Komentáře

  1. Milo #1

    avatar

    Nedávno jsem nad tím dumal. On parametr global není tak parametr, jako přepínač. Dá se použít s jakýmkoliv příkazem, tedy i create-project.

    Jeho magie spočívá v tom, že změní pracovní adresář na globální (na Linuxu /home/milo/.composer) a dál se chová stejně. Při require vytvoří composer.json, stáhne závislosti, vytvoří vendor/bin.

    A tohle, spekuluji, má fungovat tak, že si člověk přidá /home/milo/.composer/vendor/bin do $PATH a může volat binárky globálně. Jenže je to na nic, přesně z důvodů které píšeš.

    Dává mi smysl composer global create-project apigen/apigen. Jako že chci mít globálně Apigen. Jenže, tam je adresář s binárkou v /home/milo/.composer/apigen/apigen/vendor/bin a to je blbost přidávat do $PATH pro každý nový globální projekt. Zkrátka, buď to podělali nebo nedotáhli.

    před 2 lety | odpovědět | reagoval [3] ujovlado
  2. bazo http://bazo.sk #2

    avatar

    global vobec nie je nanic. napriklad tester tak mam nainstalovany. aby som nemusel pre kazdy projekt menit cestu k spustaciemu skriptu v netbeans. tester je pritom nainstalovany aj lokalne.
    je to ten isty princip ako s gulpom, tiez musi byt lokalne aj globalne nainstalovany.

    pre nastroje ktorych triedy v projekte nevyuzijeme, napr nejaky staticky analyzator, nema lokalna instalacia vobec vyznam a jedina spravna instalacia je cez global.
    dalsi priklad su dev nastroje pre phalcon framework, ktore maju tiez vyznam jedine globalne.

    ps: policko web musi obsahovat http:// trosku zbytocne, nie?

    před 2 lety | odpovědět | reagoval [5] David Grudl
  3. ujovlado http://ujovlado.sk #3

    avatar

    #1 Milo, Myslím, že riešením môže byť projekt, nazvime ho composer-bin, ktorý bude mať zadefinované závislosti na konkrétnych balíčkoch.

    Tento projekt si naklonuješ ty, tvoji kolegovia, a všetci, ktorí pracujú. Dáš si ho napríklad do /home/milo/composer-bin/.

    Následne si do path pridáš bin priečinok tohto projektu – t.j. /home/milo/composer-bin/vendor/bin.

    Všetci tak dostanete tie isté závislosti a je úplne jedno, kde si ho kto naklonuje.

    Jednoducho povedané, zvlášť projekt pre php binárky.

    před 2 lety | odpovědět | reagoval [4] Milo
  4. Milo #4

    avatar

    #3 ujovlado, Snad jsem Tě pochopil… ale je to to samé, jako composer global require, jen do jiného adresáře. Tím se případné kolizi závislostí nevyhneš.

    Osobně na composer global kašlu. V $PATH mám adresář /home/milo/bin a do něj si linkuji. Např:

    apigen -> /var/www/dev/apigen/apigen/bin/apigen
    apigen-2.8.1 -> /home/milo/tools/apigen-2.8.1/vendor/bin/apigen
    php7 -> /home/php/7.0.0-dev/bin/php
    php7-cgi -> /home/php/7.0.0-dev/bin/php-cgi

    Pak už je jedno, kde co je.

    před 2 lety | odpovědět | reagoval [6] ujovlado
  5. David Grudl http://davidgrudl.com #5

    avatar

    #2 bazo, tak si schválně zkus globálně nainstalovat třeba tohle:
    https://github.com/…l-is-useless

    ps: že adresa musí obsahovat http:// zbytečné je, ale hlásí to prohlížeč, nikoliv web.

    před 2 lety | odpovědět
  6. ujovlado http://ujovlado.sk #6

    avatar

    #4 Milo, áno, pochopil si to správne. Ja som to najprv pochopil trošku inak, t.j., že riešime rôzne verzie balíčkov rôznych developerov, a nie kolízie balíčkov medzi sebou. Pardon. :)

    Vyriešil by som to asi nejako takto, custom install.sh skriptom:
    https://github.com/…poser-global

    před 2 lety | odpovědět

Zanechat komentář

Text komentáře
Kontakt

(kvůli gravataru)



*kurzíva* **tučné** "odkaz":http://example.com /--php phpkod(); \--