Autor | Zpráva | ||
---|---|---|---|
quatzael Profil |
Chci nějak vyřešit tohle co je v ukázce a samozřejmě nefunguje. Jde to prosím nějak?
$array['aaa']['bbb']['ccc'] = "value"; $subarray = "['bbb']['ccc']"; echo $array['aaa']$subarray; //má zobrazit to samé co $array['aaa']['bbb']['ccc'] tedy "value" |
||
Alphard Profil |
#2 · Zasláno: 26. 10. 2015, 09:02:31
Jedině si naimplementovat nějakou funkci, která přejde na další úrovně zanoření
echo getByKeys($array['aaa'], ['bbb', 'ccc']); |
||
quatzael Profil |
#3 · Zasláno: 26. 10. 2015, 12:46:28
A takhle by to nějak nešlo?
$array["aaa"]["bbb"]["ccc"] = "value"; $string = 'echo $array["aaa"]["bbb"]["ccc"];'; parse_str($string); Tohle teda taky nefunguje, ale moc nechápu proč.. |
||
Joker Profil |
#4 · Zasláno: 26. 10. 2015, 12:47:28
quatzael:
On je podezřelý už ten požadavek, protože to "['bbb']['ccc']" je v podstatě kus PHP kódu, takže by na to spolehlivě fungoval leda eval, což není dobré řešení.
Řešení by bylo na začátku mít místo řetězce pole těch indexů: array("bbb", "ccc") , pak to bude fungovat bez problému.
|
||
quatzael Profil |
Joker:
Ok, já s tím polem indexů problém nemám, ale vůbec nerozumím jak to bude fungovat s tím parse_str ..Joker: Hele ale ten eval funguje!! tak to zase není až tak moc špatný řešení, ne? Joker: Díky moc! |
||
Joker Profil |
#6 · Zasláno: 26. 10. 2015, 13:12:27
quatzael:
„Hele ale ten eval funguje!! tak to zase není až tak moc špatný řešení, ne?“ … Já vůl, jsem mohl čekat, že to takhle skončí. „Ok, já s tím polem indexů problém nemám“ Tak v tom případě je to úplně jednoduché, ne? $keys = array("aaa", "bbb", "ccc"); $val = $arr[$keys[0]][$keys[1]][$keys[2]]; Je to prostě index pole v proměnné. |
||
Dan Charousek Profil |
#7 · Zasláno: 26. 10. 2015, 13:25:53
Joker:
Něco mi říká, že počet indexů bude proměnlivý. „Já vůl, jsem mohl čekat, že to takhle skončí.“ Snad ještě není pozdě :-) quatzael: „Hele ale ten eval funguje!! tak to zase není až tak moc špatný řešení, ne?“ Vlastně je. Eval by se měl používat opravdu jen vzácně. Napíšeš-li do googlu why not use eval, dozvíš se víc. V tvém případě bych volil řešení, které navrhl Alphard asice implementovat vlastní getByKeys() funkci.
Ta funkce by mohla vypadat třeab takto: <?php function getByKeys(array $array, $keys) { $temp = $array; $length = count($keys); for($i = 0; $i < $length; $i++) { $key = $keys[$i]; if(isset($temp[$key]) && ($i < $length - 1)) { $temp = $temp[$key]; } elseif(isset($temp[$key])) { return $temp[$key]; } else { throw new Exception("Argument out of range exception, undefined key '$key'"); } } } $myArray = [ "aaa" => [ "bbb" => [ "ccc" => "Hello world!" ] ] ]; try { var_dump(getByKeys($myArray["aaa"], ["bbb", "ccc"])); } catch(Exception $e) { echo "Error: " . $e->getMessage(); } |
||
quatzael Profil |
#8 · Zasláno: 26. 10. 2015, 13:34:07
Joker:
Dík, to sice funguje, ale asi neřeší ten problém, který jsem nezmínil, a to ten, že potřebuju, aby tam šlo takhle přidávat i delší ocas. Tzn. když nebudu mít jen $subarray = "['bbb']['ccc']"; $subarray = "['bbb']['ccc']['ddd']"; |
||
Dan Charousek Profil |
#9 · Zasláno: 26. 10. 2015, 13:39:25
quatzael:
To řeší moje funkce z [#7] |
||
quatzael Profil |
Dan Charousek:
Asi jo, sorry, ještě jsem nerefreshoval, než jsem to psal.. Teď na to koukám.. Dan Charousek: Ještě, abych upřesnil úplně o co mi jde. Jedná se o proměnnou v metodě jedné třídy a je hodně rozvětvená. $array['aaa']['branch1']['subbranch1']; $array['aaa']['branch1']['subbranch2']; $array['aaa']['branch2']['subbranch1']; $array['aaa']['branch2']['subbranch2']; A ještě víc všelijak rozvětvená struktura.. A já potřebuju každý tý větvi přiřadit konkrétní hodnotu. S tím, že prakticky vždycky budu mít $array['aaa'] a potřebuju k ní připojit ten ocas a nastavit celé té větvi nějakou hodnotu.
Hlavně, aby se ta hodnota nastavila globálně a ne jenom uvnitř té funkce getByKeys .
To echo v příkladu jsem uvedl jen jako ukázku. Fakticky jde o přiřazování hodnot..
|
||
Dan Charousek Profil |
#11 · Zasláno: 26. 10. 2015, 18:52:00
quatzael:
V tom případě by ta funkce mohla vypadat takto: <?php function iterate(&$array, $keys, $assign, $i = 0) { foreach($array as $key => &$value) { if(!isset($keys[$i+1]) && !empty($assign)) { $value = $assign; return; } elseif(!isset($keys[$i])) { return $value; } if($keys[$i] != $key) { continue; } $i++; if(is_array($value)) { return iterate($value, $keys, $assign, $i); } else { if(empty($assign)) { return $value; } else { $value = $assign; } } } } function findByKey(array &$array, array $keys, $assign = null) { return iterate($array, $keys, $assign); } $array = [ "aaa" => [ "bbb" => [ "ccc" => "Hello world!" ] ] ]; echo "<pre>"; var_dump(findByKey($array["aaa"], ["bbb"])); // Vrátí Hello World! findByKey($array, ["aaa", "bbb", "ccc"], "World Hello!"); var_dump($array); // Vytiskne pole - [aaa][bbb][ccc] bude mít novou hodnotu `World Hello!` echo "</pre>"; |
||
Alphard Profil |
#12 · Zasláno: 26. 10. 2015, 19:41:32
Tak to už je hodně velká lidová tvořivost :-) co třeba vrátit si referenci?
function &getByKeys(array &$input, array $keys) { $iter = &$input; foreach ($keys as $key) { if (!isset($iter[$key])) { throw new Exception("Argument out of range exception, undefined key '$key'"); } $iter = &$iter[$key]; } return $iter; } |
||
Dan Charousek Profil |
#13 · Zasláno: 26. 10. 2015, 19:53:40
Alphard:
Děkuji, toto mě posunulo o dost dál :) |
||
Fisir Profil |
Reaguji na quatzaela:
Já teda nerad posílám kompletní hotová řešení, ale v tomto případě je to méně evil než eval .
function &access(&$array, $path){ if(!is_array($array)){ throw new \InvalidArgumentException('Argument $array expected to be an array.'); return; } if(!is_string($path)){ throw new \InvalidArgumentException('Argument $path expected to be a string.'); return; } if(empty($path)){ throw new \UnexpectedValueException('Argument $path cannot be empty.'); return; } if(preg_match_all('/\[(["\']?)(.*?)(\\\\){0}\\1\]/u', $path, $matches, PREG_SET_ORDER) > 0){ $result = &$array; foreach($matches as $match){ $key = str_replace('\\'.$match[1], $match[1], $match[2]); if(isset($result[$key])){ $result = &$result[$key]; } else { throw new \UnexpectedValueException('Argument $path points to element which doesn\'t exist.'); return null; } } return $result; } else { throw new \UnexpectedValueException('Argument $path is not a valid array pointer.'); return null; } } Pak už stačí funkci access předhodit pole a tvojí proměnnou $subarray :
$array['aaa']['bbb']['ccc'] = "value"; $subarray = "['bbb']['ccc']"; echo access($array['aaa'], $subarray); Poznámka pro pokročilé: funkce plně podporuje zpětné a externí upravování takto získaných hodnot, stačí si ji uložit do pomocné proměnné jako referenci. |
||
Dan Charousek Profil |
Fisir:
Hezké :), ale i tak si troufám říct, že zlatý bludišťák putuje Alphardovi :) quatzael: Každopádně doufám, že je jasné, že bychom se s kolegy nesnažili jen tak pro nic za nic, když bychom tě opravdu od toho eval u nechtěli odradit.
|
||
Fisir Profil |
#16 · Zasláno: 26. 10. 2015, 20:37:27
Reaguji na Dana Charouska:
Já v podstatě dělám to samé jako Alphard, akorát podporuji quatzaelem v prvním příspěvku zmíněný zápis pole jako textový řetězec a kontroluji typy parametrů. |
||
quatzael Profil |
#17 · Zasláno: 28. 10. 2015, 11:14:13
Alphard, Dan Charousek, Fisir:
Kluci díky za návrhy. Já jsem to teda už vyřešil tím evalem. Každopádně jsem zkoumal Fisirovo řešení [#14]. Ta funkce, ale pouze vrací hodnotu $array['aaa']['bbb']['ccc'] , ne?
Já jsem tady někde [#10] asi ne moc jasně upřesňoval, že potřebuju fakticky PŘIŘADIT hodnotu, ne jí echovat.. A je to celé ve třídě objektu, takže vlastně, když mám v metodě třídy tohle: $value= "value"; $path = "['bbb']['ccc']"; potřebuju, aby něco co by mi potom nahradilo řádek: $this->array['aaa']['bbb']['ccc'] = $value; S tím, že pouze vím, že tam budu mít požito to $this->array['aaa']
Já jsem toto vlákno začal trochu obecně, protože mě nenapadlo, že to bude tak komplikovaný, tak se omlouvám.. |
||
Fisir Profil |
Reaguji na quatzaela:
„Já jsem to teda už vyřešil tím evalem.“ eval() není řešení. Je to bezpečnostní díra.
„Ta funkce, ale pouze vrací hodnotu $array['aaa']['bbb']['ccc'] , ne?“
To není tak úplně pravda: $value = 'value'; $path = '["bbb"]["ccc"]'; $array = array( 'aaa' => array( 'bbb' => array( 'ccc' => 'test' ) ) ); $variable = &access($array['aaa'], $path); echo($variable); // vypíše 'test' $variable = $value; echo($array['aaa']['bbb']['ccc']); // vypíše 'value' Všimni si, že výsledek funkce access() do proměnné $variable předávám jako referenci (znak & ), takže se změnou její hodnoty změní i hodnota v původním poli (a naopak).
|
||
Dan Charousek Profil |
quatzael:
Musím si stát za tím, abys ten eval nepoužíval a zvážil použití jednoho z výše zmíněných kódů (doporučuji [#12]). Fisirův kód také umí to, co požaduješ (viz. poznámka pod čarou v [#14]) Pokud by ses rozhodl použít Alphardovu funkci, vypadalo by to asi nějak takto: $val = &getByKeys($this->array['aaa'], ['bbb', 'ccc']); $val = "Hello World!"; // nastaví novou hodnotu. var_dump($this->array['aaa']['bbb']['ccc']); // bude mít hodnotu `Hello World!` |
||
Alphard Profil |
#20 · Zasláno: 28. 10. 2015, 11:44:29
Joker [#4]:
Upřímně, tahle rada byla podle mě dost hloupá. Říct začátečníkovi o eval() v situaci, kdy ho zřejmě nepotřebuje a má své řešení blbě navržené*, nepovažuji za rozumné. Obvykle se najde někdo, kdo přispěchá s nevhodnou radou, přestože správné řešení je také velmi jednoduché :-) *Proč si myslím, že je původní návrh špatný? V [#1] a [#3] quatzael popisuje svůj záměr traverzovat přes pole. Nezdá se mi, existoval objektvní důvod trvat na popsaném formátu (např. parsování jiných scriptů), je to jen přirozený důsledek zvyklosti z klasického PHP kódu a neznalosti správného návrhu. Zdálo se mi docela rozumné zkusit mu „vnutit“ řešení [#2] Alphard, které považuji za návrhově přijatelné, je obecnější, bude mít podporu v editorech, bude lépe laditelné, atd. quatzael tady už docela dlouho pokládá základní otázky, tak proč ho trochu neučit... Fisir [#14]: Z mého pohledu neměl být quatzael v této cestě podporován, ale chápu, že to bylo myšleno jako lepší řešení než eval. K té funkci bych ale dodal, že zbytečně kombinuje 2 věci. Kdybych to psal já, vyčlením to do 2 funkcí. Jedna funkce bude parsovat vstupní řetězec, vrátí pole klíčů a předá ho druhé funkci ([#12] Alphard). Mohu se zeptat, proč tam uvádíš return statement za throw? Je to unreachable code. Alphard [#12]: Kdyby mělo přiřazení fungovat jako setter, nevidím problém v přidání 3 parametru a přiřazení na 9. řádku. |
||
Fisir Profil |
#21 · Zasláno: 28. 10. 2015, 11:55:28
Reaguji na Alpharda:
„Kdybych to psal já, vyčlením to do 2 funkcí.“ Já bych z toho udělal třídu. Ale nejsem si úplně jistý, jestli by to quatzaelovi nějak pomohlo. „proč tam uvádíš return statement za throw?“ Hm, to vážně netuším :-). |
||
quatzael Profil |
Fisir:
„ eval() není řešení. Je to bezpečnostní díra.“
To je bezpečnostní díra snad jen tehdy, když do toho vkládáš nějaké externí hodnoty. Tohle ale není vůbec můj případ. Normálně bych eval nepoužil, ale tady se to zdá být jednoznačně nejvýhodnější, protože jedním řádkem udělám snadno to co jinak složitě třiceti.. [#14] Fisir Alphard: „quatzael tady už docela dlouho pokládá základní otázky, tak proč ho trochu nemučit...“:o)) Díky za učení, hlavně ohledně toho předávání reference, to je pro mě novinka. Ale bude to potom správně fungovat? Když tam používáš ten foreach , tak se tam to pole postupně přepisuje, ne? Takže v části kdy se přepisuje hodnota $array['aaa']['bbb'] a přidává se k němu ['ccc'] tak se smaže případný obsah, který byl ve větvi $array['aaa']['bbb']['eee'] .. A já samozřejmě potřebuju mít všechny ostatní větve naprosto nedotčeny..
|
||
tiso Profil |
#23 · Zasláno: 28. 10. 2015, 12:43:56
quatzael: „A já samozřejmě potřebuju mít všechny ostatní větve naprosto nedotčeny..“
To je taký problém to vyskúšať? |
||
Časová prodleva: 7 let
|
0