Má znak @ nějaký hlubší význam?

tomve
Člen | 11
+
-3
-

Zdravím,

všiml jsem si, že v určitých funkcích se používá @.
Ze zvědavosti se chci zeptat, zda to má hlubší význam než umlčení.

Např. read() v Filesystem

public static function read($file)
{
 	     $content = @file_get_contents($file); // @ is escalated to exception
         if ($content === false) {
             throw new Nette\IOException("Unable to read file '$file'.");
         }
         return $content;
}

Osobně bych použil nejprve file_exists() a file_get_contents() až s return. Ale chápu, že file_get_contents() má pár nevýhod, i když…

  • false pro symlinks, mohl by nastat problém,
  • false s zapnutým safe_mode(), který není od 5.4,
  • někdy false pro soubory 2+ GB na 32bit, moc jich dnes nebude.

Tak nevím, zda @ je legacy kód nebo je v tom něco víc, jelikož mi přijde trochu „tvrdé“ použit hned file_get_contents(). (Kdysi mi neexistuji soubory, které jsem hned četl, „zavařily“ vps.)

duke
Člen | 650
+
+3
-

tomve napsal(a):

Osobně bych použil nejprve file_exists() a file_get_contents() až s return.

Tam bys ale mohl narazit na problém, že v momentu, kdy voláš file_exists() ještě soubor existuje a v momentu, kdy voláš file_get_contents() už ne (jiný skript mohl soubor mezi tím smazat), takže bys to musel stejně znovu řešit i pro file_get_contents().

tomve
Člen | 11
+
0
-

duke napsal(a):

tomve napsal(a):

Osobně bych použil nejprve file_exists() a file_get_contents() až s return.

Tam bys ale mohl narazit na problém, že v momentu, kdy voláš file_exists() ještě soubor existuje a v momentu, kdy voláš file_get_contents() už ne (jiný skript mohl soubor mezi tím smazat), takže bys to musel stejně znovu řešit i pro file_get_contents().

Nebo obsah se získá, mezitím se soubor smaže a return vrátí „neexistující“ obsah.

Asi jsem haklivější na neověřování a umlčování. Just saying.

GEpic
Člen | 562
+
0
-

Můžeš to checkovat jak chceš, ale někdo ti může do file_get_contents dát klidně URL. A mě se zde líbí, že místo warningu dostaneš exception, s tou se vypořádává daleko lépe. Než nastavovat navíc ještě nějaké error handlery a podobně.

tomve
Člen | 11
+
0
-

GEpic napsal(a):

Můžeš to checkovat jak chceš, ale někdo ti může do file_get_contents dát klidně URL. A mě se zde líbí, že místo warningu dostaneš exception, s tou se vypořádává daleko lépe. Než nastavovat navíc ještě nějaké error handlery a podobně.

String se dá vždy vyřešit / ověřit.

Avšak díky za diskusi, jsem se chtěl dozvědět něco a skončil jsem v mínusu.

GEpic
Člen | 562
+
0
-

@duke ti to popsal hezky a z toho jednoho mínusu si nic nedělej :) … navíc do file_get_contents ti někdo může předat klidně i URL ve tvaru http://neco.cz, a na to už ti file_exists nestačí

tomve
Člen | 11
+
0
-

@CZechBoY To chápu, avšak u read() to jde použít tuto logiku naopak (psal jsem nahoře) – file_get_contents() získá obsah, mezitím se soubor smaže a return vrátí „neexistující“ / „cache“ obsah.

@GEpic String se dá ověřit, zda je url nebo cesta – dokonce je tam isAbsolute().

Napadlo mě napsat něco jako safe_read() a exists() – v Filesystem nic takového nevidím, ale zase bych skončil u read() s @ (kdybych nechtěl psát další file_get_contents()) . :D

Editoval tomve (22. 7. 2018 14:18)

tomve
Člen | 11
+
0
-

@GEpic Uznávám, že si mě s tím URL dostal a mělo mi to dojít dřív. Pokud dáš před file_get_contents() funkci file_exists() a string bude URL, tak file_exists() vrátí false (pracuje pouze s lokálem) a do file_get_contents() se to nikdy nedostáne.

Editoval tomve (23. 7. 2018 11:33)

David Matějka
Moderator | 6445
+
+4
-

hlavni problem, jak zminoval @duke, je s tou atomicitou. pokud bys pred tim mel file_exists a nasledne file_get_contents bez @, tak by ti nahodne mohly vyskakovat warningy

jelikoz se potlaceny warning eskaluje na exception, tak je pouziti @ zcela legitimni.

hacafrakus
Člen | 14
+
+11
-

To, že metoda read() může vrátit smazaná data není problém (protože to není její účel) a kontrola přes file_exists() by tomu nijak nezabránila. Vydedukovat z toho, že Nette programátor neumí programovat, mi připadá fascinující.

Editoval hacafrakus (28. 7. 2018 17:27)

tomve
Člen | 11
+
-14
-

hacafrakus napsal(a):

To, že metoda read() může vrátit smazaná data není problém (protože to není její účel) a kontrola přes file_exists() by tomu nijak nezabránila. Vydedukovat z toho, že Nette programátor neumí programovat, mi připadá fascinující.

To nebylo napsáno jen kvůli read() funkci.

Mě osobně přijde neskutečný fakt, že nette je nejpoužívanější framework v ČR, ale komunita okolo něj není schopná nette vyvíjet. Pak se musí udělat crowfunding.

Tyhle a další věci mě přijdouá fascinující a přesvědčují mě pořád dookola, že většina nettistů neumí programovat.

Editoval tomve (29. 7. 2018 11:07)

Mysteria
Člen | 797
+
+1
-

Děláš jako kdyby ostatní frameworky peníze na vývoj nevybíraly. Sice to nedělají jako Nette, ale tečou tam třeba přes školení a dalšími způsoby.

A co se týká komunity a toho, že není schopná Nette vyvíjet, tak to je nesmysl, protože to že Nette používáš ještě neznamená, že si rovnou můžeš troufnout ho vyvíjet. Nebo ty snad taky když jezdíš autem, tak si schopnej ho i vyrábět? Já teda ne.

A co se týká @ v kódu, tak můžeš začít třeba se Symfony, zeptat se jich proč je taky používají, když je to nepřekonatelný problém. :)

David Grudl
Nette Core | 8082
+
0
-

@tonve, ty se podílíš na vývoji nějakého frameworku, nebo neumíš programovat? ;-)

tomve
Člen | 11
+
0
-

@Mysteria Pokud si nikdo netroufne, tak vývoj bude vždy stát na několika osobách, které budou muset být placení.

@DavidGrudl Roky jsem programoval v čistém PHP (a pokukoval po Nette, jak si vede). Pak jsem před 2 lety skončil u Laravelu a teď jsem si řekl, že se podívám blíže na Nette (proto ten dotaz) – nedávno jsem viděl paskvil stvořen nettistou, který půlku kódu udělal natvrdo.
Jinak se na tvorbě frameworku nepodílím.

Milo
Nette Core | 1283
+
+1
-

@tomve Napsal bys sem kód, jak bys to vyřešil ty?

Milo
Nette Core | 1283
+
0
-

@tomve Napsal bys sem kód, jak bys to vyřešil ty?

tomve
Člen | 11
+
0
-

@Milo Nějakou představu jsem tady už napsal:

Zbytek jsou písmena a řádky.

@DavidGrudl Možná by bylo dobré u těch mínusových příspěvků, které „zešediví“, aby hoverem zpět „zčernalý“ – blbě se to čte (osobně mi to nevadí).

Editoval tomve (29. 7. 2018 17:09)

Milo
Nette Core | 1283
+
+1
-

To jo, četl jsem celou diskuzi. Chtěl bych ale vidět konkrétní kód, abychom to případně fixnuli.

tomve
Člen | 11
+
0
-

Až se k tomu dostanu, tak to jsem napíšu.

Včera jsem zkoušel na localhostu s php7.2.7 co to udělá s 10k requestů na (ne)existujicí soubory – čisté php, v nette jsem to ještě netestoval.

U neexistujících souborů trvál:

U existujících souborů:

  • file_exists() s clearstatfile() cca 0.015s
  • @file_get_contents() cca 0.17s
  • file_exists() s clearstatfile() a s @file_get_contents() cca 0.19s

btw: Existující soubor byl FileSystem.php

Editoval tomve (30. 7. 2018 12:44)

hacafrakus
Člen | 14
+
+2
-

Co takový test vlastně měří a jak souvisí s implementací metody určené ke čtení? Zkusím znovu popsat, proč není kontrolována existence souboru:

  • file_get_contents() načte obsah souboru a vrátí FALSE, pokud se to z libovolného důvodu nepodaří
  • file_exists() následovaný file_get_contents() je sice teoreticky rychlejší při čtení velkého počtu neexistujících souborů, jenomže to není atomická operace – mezi těmito dvěma voláními může dojít ke smazání souboru, ve webové aplikaci to není zrovna nepravděpodobný scénář. Taková metoda by naopak byla špatná, protože by klidně vrátila FALSE a produkovala warning a pokud by to programátor neošetřil (k čemuž jej výjimka nutí), vůbec by se o problému nedozvěděl.
  • Implementace s file_exists() by musela kontrolovat také oprávnění, klidně to můžete zahrnout do toho testu – ať už měříte cokoliv. Mimochodem, nepřekvapivě v něm v případě čtení existujícího souboru dojde k tomu, že nejdříve provedete všechny kontroly existence a oprávnění, aby je následně file_get_contents() svým způsobem provedl také (sice to, pokud vím, nedělá, ale při čtení existujících souborů – což je podle mě nejčastější – bude taková metoda vždy pomalejší).

To, že metoda vrátí obsah souboru, který vzápětí někdo smaže, je sice možné, ale file_exists() to nijak neřeší. Kromě toho smyslem metody read() je soubor přečíst a vrátit obsah, ne zajistit, aby vrácený obsah stále existoval.

Samozřejmě se rád nechám vyvést z omylu a ocením kód, který bude naplňovat poslání dané metody, zajistí atomicky bezpečné čtení a bude navíc výkonnější. Momentálně žiji v přesvědčení, že takový způsob neexistuje.

Editoval hacafrakus (30. 7. 2018 13:03)

tomve
Člen | 11
+
0
-

Pointa toho vše je / má být, aby se zbytečně nedělaly requesty na neeexistující soubory (můj původní příspěvek), a taky jsem se ze zvědavosti ptál na @.

Pak se, zde začlo argumentovat, že v té době file_exists může vrátit true a contents warning (bez @, což bych tedy brál, i když jsem nikdy nedostál warning u contents bez @ po file_exists) a já zase protiargumentoval, že read() může vrátit obsah souboru, který se mezitím může smazat.

hacafrakus
Člen | 14
+
0
-

Pokud vám vadí zbytečné requesty na neexistující soubory, doporučil bych je asi nedělat – zbytek byl snad vysvětlen.

Ještě k STFU operátoru – file_get_contents() generuje při chybě warning, který metoda přeloží na exception. Důvod je prostý – warning nezastaví kód, exception ano – tak automaticky donutí programátora podobný stav ošetřit, nebo alespoň nenapáchá nějaké kolaterální škody.

tomve
Člen | 11
+
0
-

hacafrakus napsal(a):

Pokud vám vadí zbytečné requesty na neexistující soubory, doporučil bych je asi nedělat – zbytek byl snad vysvětlen.

Ještě k STFU operátoru – file_get_contents() generuje při chybě warning, který metoda přeloží na exception. Důvod je prostý – warning nezastaví kód, exception ano – tak automaticky donutí programátora podobný stav ošetřit, nebo alespoň nenapáchá nějaké kolaterální škody.

To je taky určitá možnost.

Díky za diskusi. Více k tématu již nemám co napsát.

Milo
Nette Core | 1283
+
0
-

@tomve Pokud měl být příspěvek o tom, aby se nedělaly zbytečné filesystem operace, dovolím si konstatovat, že to z nadpisu ani prvního příspěvku, nikdo tak nepochopil :o)

Podle uvedeného měření file_exists() (IMHO by ale mělo být is_file()) by se dala asi mikrooptimalizace udělat. Nicméně, shut-up operátor se stejně s file_get_contnents() musí použít.

duke
Člen | 650
+
0
-

tomve napsal:

Pointa toho vše je / má být, aby se zbytečně nedělaly requesty na neeexistující soubory (můj původní příspěvek), a taky jsem se ze zvědavosti ptál na @.

Pak se, zde začlo argumentovat, že v té době file_exists může vrátit true a contents warning (bez @, což bych tedy brál, i když jsem nikdy nedostál warning u contents bez @ po file_exists) a já zase protiargumentoval, že read() může vrátit obsah souboru, který se mezitím může smazat.

Stále mám za to, že řešení použité v Nette, je nejrozumější. Extrémní „pesimistický“ scénář, který jsi zmínil (tj. obrovské množství neexistujících souborů, které chceš tímto způsobem číst), lze kdykoli zoptimalizovat vlastním voláním is_file. Ale ruku na srdce, jak často k takovému scénáři může dojít? Daleko běžnější je „optimistický“ scénář, kdy soubor existuje, a pak je naopak optimálnější is_file nevolat, neboť stejnou kontrolu stejně musí řešit interně metoda file_get_contents, a navíc odpadá problém s neatomicitou (jehož nejelegantnější řešení by si stejně vynutilo použít operátor @).

Co se týče tvého protiargumentu, že read() může vrátit obsah souboru, který je v momentu návratu funkce read() již smazán, zajímalo by mě, jak bys chtěl zajistit opak. Nicméně souhlasím s názorem těch, kteří tvrdí, že není úkolem read() toto zajistit, ale prostě přečíst obsah a pak ho vrátit bez ohledu na to, co se následně děje s jeho zdrojem.