it-swarm-eu.dev

Zadejte proměnné obsazení v PHP, jaký je praktický důvod k tomu?

PHP, jak většina z nás ví, má slabé psaní . Pro ty, kteří ne, PHP.net říká:

PHP nevyžaduje (nebo nepodporuje) explicitní definici typu v deklaraci proměnné; typ proměnné je určen kontextem, ve kterém je proměnná použita.

Milovat to nebo nenávidět, PHP re-casting proměnné za běhu. Takže následující kód je platný:

$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)

PHP také umožňuje explicitní obsazení proměnné, například:

$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"

To je všechno v pohodě ... ale za život mně si nedokážu představit praktický důvod, proč to udělat.

Nemám problém se silným psaním v jazycích, které jej podporují, jako je Java. To je v pořádku a já tomu úplně rozumím. Také jsem si vědom - a plně chápu užitečnost - typ hinting ve funkčních parametrech.

Problém, který mám s odléváním typu, je vysvětlen výše uvedenou citací. Pokud PHP umí zaměnit typy podle přání , může tak učinit i po vás force casting typ; a může tak učinit on-the-fly , když potřebujete určitý typ v operaci. To znamená, že platí následující:

$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"

Jaký to má smysl?


Vezměte tento teoretický příklad světa, kde uživatelsky definovaný typ casting má v PHP smysl :

  1. Vynutíte obsazení proměnné $foo jako int(int)$foo.
  2. Pokoušíte se uložit hodnotu řetězce do proměnné $foo.
  3. PHP vyvolá výjimku !! ← To by mělo smysl. Najednou existuje důvod pro uživatelem definovaný typ obsazení!

Skutečnost, že PHP bude přepínat věci podle potřeby, způsobuje, že uživatelem definovaný typ je casting nejasný. Například následující dva ukázky kódu jsou ekvivalentní:

// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

Rok poté, co se původně na tuto otázku zeptal, hádejte, kdo zjistil, že používá typcasting v praxi? S pozdravem.

Požadavkem bylo, aby se na webových stránkách zobrazovaly hodnoty peněz pro menu restaurace. Návrh webu vyžadoval, aby byly oříznuty koncové nuly, takže displej vypadal přibližně takto:

Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3

Nejlepší způsob, jak jsem zjistil, že to bylo promrhat proměnnou jako float:

$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;

PHP ořízne koncové nuly plováku a pak plovoucí plovák přepíše jako řetězec pro zřetězení.

45
Stephen

Ve slabě typovaném jazyce existuje odlišení typů k odstranění dvojznačnosti v typizovaných operacích, pokud by jinak kompilátor/interpret použil pořadí nebo jiná pravidla k vytvoření předpokladu, kterou operaci použít.

Normálně bych řekl, že PHP následuje tento vzorec, ale z případů, které jsem zkontroloval, PHP se v každém choval kontra intuitivně).

Zde jsou tyto případy, které používají JavaScript jako srovnávací jazyk.

String Concatentation

To samozřejmě není problém v PHP, protože existují oddělené řetězové zřetězení (.) a sčítání (+) operátory.

JavaScript
var a = 5;
var b = "10"
var incorrect = a + b; // "510"
var correct = a + Number(b); // 15

Porovnání řetězců

V počítačových systémech je často „5“ větší než „10“, protože jej nevykládá jako číslo. Není tomu tak v PHP, které, i když obě jsou řetězce, zjistí, že jsou to čísla a odstraňuje potřebu obsazení):

JavaScript
console.log("5" > "10" ? "true" : "false"); // true
PHP
echo "5" > "10" ? "true" : "false";  // false!

Psaní podpisu funkce

PHP implementuje kontrolu funkčních podpisů typu holých kostí, ale bohužel je tak chybný, že je pravděpodobně použitelný jen zřídka.

Myslel jsem, že možná dělám něco špatně, ale komentář k dokumentům potvrzuje, že vestavěné typy jiné než pole nelze použít v PHP podpisy funkcí - i když chybová zpráva je zavádějící.

PHP
function testprint(string $a) {
    echo $a;
}

$test = 5;
testprint((string)5); // "Catchable fatal error: Argument 1 passed to testprint()
                      //  must be an instance of string, string given" WTF?

A na rozdíl od jiných jazyků, které znám, i když použijete typ, kterému rozumí, null již nelze předat tomuto argumentu (must be an instance of array, null given). Jak hloupé.

Booleovská interpretace

[ Upravit ]: Toto je nové. Přemýšlel jsem o jiném případě a logika je opět obrácena z JavaScriptu.

JavaScript
console.log("0" ? "true" : "false"); // True, as expected. Non-empty string.
PHP
echo "0" ? "true" : "false"; // False! This one probably causes a lot of bugs.

Na závěr, jediný užitečný případ, na který mohu myslet, je ... (buben)

Zadejte zkrácení

Jinými slovy, pokud máte hodnotu jednoho typu (řekněme řetězec) a chcete ji interpretovat jako jiný typ (int) a chcete ji přinutit, aby se stala jednou z platné sady hodnot tohoto typu:

$val = "test";
$val2 = "10";
$intval = (int)$val; // 0
$intval2 = (int)$val2; // 10
$boolval = (bool)$intval // false
$boolval2 = (bool)$intval2 // true
$props = (array)$myobject // associative array of $myobject's properties

Nevidím, co by tě vyvrhlo (na typ, který zahrnuje více hodnot).

Takže zatímco nesouhlasím s vaším navrženým použitím psaní (v zásadě navrhujete statické psaní , ale s dvojznačností, že pouze pokud by to bylo force-cast do typu, to vyvolá chybu - což by způsobilo zmatek), myslím, že je to dobrá otázka, protože zřejmě casting má velmi velmi účelný v PHP.

32
Nicole

Mícháte koncepty slabého/silného a dynamického/statického typu.

PHP je slabé a dynamické, ale váš problém je s konceptem dynamického typu. To znamená, že proměnné nemají typ, hodnoty ano.

‚Lití typu 'je výraz, který vytváří novou hodnotu jiného typu originálu; nedělá nic pro proměnnou (pokud je zapojena).

Jedna situace, kdy pravidelně zadávám hodnoty obsazení, je na numerických parametrech SQL. Měli byste dezinfikovat/uniknout jakékoli vstupní hodnotě, kterou vložíte do příkazů SQL, nebo (mnohem lépe) použít parametrizované dotazy. Ale pokud chcete nějakou hodnotu, která MUSÍ být celé číslo, je mnohem snazší ji pouze obsadit.

Zvážit:

function get_by_id ($id) {
   $id = (int)$id;
   $q = "SELECT * FROM table WHERE id=$id LIMIT 1";
   ........
}

pokud jsem vynechal první řádek, $id by byl snadný vektor pro SQL injekci. Obsazení zajišťuje, že je to neškodné celé číslo; jakýkoli pokus o vložení nějakého SQL by jednoduše vyústil v dotaz na id=0

15
Javier

Jedno použití pro obsazení typu PHP, které jsem našel:

Vyvíjím aplikaci Android, která zadává http požadavky na PHP skripty na serveru) k načtení dat z databáze. Skript ukládá data ve formě objektu PHP (nebo asociativní pole)) a je vrácena jako objekt JSON do aplikace. Bez obsazení typu bych obdržel něco podobného:

{ "user" : { "id" : "1", "name" : "Bob" } }

Ale pomocí PHP typ casting (int) na ID uživatele při ukládání objektu PHP=), místo toho se mi to vrátí do aplikace:

{ "user" : { "id" : 1, "name" : "Bob" } }

Když je v aplikaci analyzován objekt JSON, ušetří mi to nutnost analyzovat id na celé číslo!

Viz, velmi užitečné.

4
Ryan

Jedním příkladem jsou objekty s metodou __toString: $str = $obj->__toString(); vs $str = (string) $obj;. Ve druhém je mnohem méně psaní a navíc je interpunkční znaménko, které trvá déle. Také si myslím, že je čitelnější, i když ostatní mohou nesouhlasit.

Dalším je výroba jednoprvkového pole: array($item); vs (array) $item;. Tím umístíte jakýkoli skalární typ (celé číslo, prostředek atd.) Do pole.
Alternativně, pokud $item je objekt, jeho vlastnosti se stanou klíči k jejich hodnotám. Myslím si však, že převod objektu -> pole je trochu divný: soukromé a chráněné vlastnosti jsou součástí pole a přejmenovány. Chcete-li citovat dokumentace PHP : soukromé proměnné mají název třídy připojený k názvu proměnné; chráněné proměnné mají před názvem proměnné '*'.

Dalším využitím je převod dat GET/POST na vhodné typy pro databázi. MySQL to zvládne samo, ale myslím, že servery kompatibilnější s ANSI mohou data odmítnout. Důvod, proč uvádím pouze databáze, spočívá v tom, že ve většině ostatních případů budou data na něm prováděna podle typu v určitém okamžiku (tj. Int/floats obvykle provedou výpočty atd.).

3
Alan Pearce

Lze jej také použít jako rychlou a špinavou metodu, která zajistí, že nedůvěryhodná data nebudou narušena, např. Pokud používáte vzdálenou službu, která má ověřené svinstvo a musí přijímat pouze čísla.

$amount = (float) $_POST['amount'];

if( $amount > 0 ){
    $remoteService->doacalculationwithanumber( $amount );    
}

Je zřejmé, že toto je chybné a také je implicitně řešeno operátorem porovnání v příkazu if, ale je užitečné zajistit, abyste přesně věděli, co váš kód dělá.

0
Gruffputs

Tento skript:

$tags = _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}

bude v pořádku pro script.php?tags[]=one ale pro script.php?tags=one, protože _GET['tags'] vrátí pole v prvním případě, ale ne ve druhém. Protože skript je zapsán tak, aby očekával matici (a máte menší kontrolu nad řetězcem dotazů odeslaným do skriptu), lze problém vyřešit vhodným vylisováním výsledku z _GET:

$tags = (array) _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}
0
beldaz