ugrás a tartalomhoz

Többdimenziós tömb elemének érték dinamikusan

Dualon · 2006. Júl. 5. (Sze), 19.48
Config változókat többdimenziós tömbben szeretnék tárolni. Ezt a tömböt adott esetben futásidőben kell bővíteni, ez viszont nem akar sikerülni.
function cfg_set($s_var_path, $m_var_value)
{
	// CONFIGVALTOZOK
	static $CFG = array(
		'db' => array(
			'tbl' => array(
				'users' => 'felhtabla',
				'forum' => 'forumtabla'
			)
		)
	);

	// CFG SET/GET
	$a_cfg_nodes = explode(':', $s_var_path);

	$s_last_node = $a_cfg_nodes[count($a_cfg_nodes)-1];
	$s_node_path = 'CFG';
	
	foreach($a_cfg_nodes as $node) {
		if ($node==$s_last_node) { // utolso node -> beallitjuk az erteket
			$var = $s_node_path."['$node']";
			${$var} = $m_var_value;
		} else { // egyebkent felepitjuk a node-hoz a tombben vezeto utat
			$s_node_path .= "['$node']";
		}
	}
	
	print_r($CFG);
}
$s_var_path: 'db:tbl:users' jellegű string
$m_var_value: az érték, amit szeretnék beállítani

Az elgondolásom az, hogy végigjárom az $s_var_path-ban megadott útvonalat a tömb adott eleméig (node), ezt az utat stringben rögzítem ($s_node_path), majd $$var-ként változóvá "konvertálva" gyorsan értéket adok neki.

Ami a fenti kódon kívül még eszembe jutott/próbáltam:
  • Referenciaként visszaírni $CFG-be (${$var} &= $m_var_value;) - Undefined variable: CFG['db']['tbl']['users'] a válasz, ráadásul ez új configváltozó esetén nem járható út
  • array_push(), array_walk() - egyikben sem láttam a számomra megfelelő megoldást. Az array_walk()-nál olvastam, hogy a callback függvényben nem lehet módosítani az eredeti tömböt, mert annak megjósolhatatlan lesz az eredménye... nem tudom eldönteni, ez vonatkozik-e rám. :)
  • Google, WL kereső (create dinamic(ally) array +PHP, tömb +dinamikus +PHP, stb...)


Már kellően sokat harcolásztam vele ahhoz, hogy lassan át sem látom. Örömmel fogadnék minden tanácsot akár a fenti megvalósítással, akár egy teljesen új megközelítéssel kapcsolatban!
Előre is kösz.
 
1

INI?

janoszen · 2006. Júl. 6. (Cs), 00.11
Hmmm... egy tipp, én parse_ini_file paranccsal egy INI fájlból parsoltatom a beállításokat egy asszoc arraybe és még soha nem volt olyan bajom, hogy nem lett volna elég flexibilis...
2

Nem rossz, csak írás?

Dualon · 2006. Júl. 6. (Cs), 00.28
Köszönöm az ötletet, az ini nem rossz, egy fő gondom van vele: az egész .ini-t újra kell írnom, ha egy értéket átírok (ha nem így van, kérlek cáfolj meg).

Változott értékek futásidőn kívüli rögzítésére nincs szükségem, ezért pl. egy xml-alapú ötletem is elvetettem már.

Átnéztem a korábban itt, a Weblaboron zajlott config konstansokban vs egyébben szálat, meg találtam a manualban a megjegyzések közt writeINIfile() függvényt, szóval végső megoldásként működhet, de egyenlőre még keresem az boldogító utat. :)

A változók érvényességi körén gondolkodtam még a témaindító problémával kapcsolatban, de nem jutottam előbbre.

Az érték lekérése megy simán, később közzéteszem azt is.
5

Nem akkora overhead...

janoszen · 2006. Júl. 6. (Cs), 08.10
Nekem nem volt akkora az overhead, mert kb 1000 vagy 10000 olvasásra jutott egy írás. Csináltam rá egy INIData osztályt, amellyel ki lehetett írni az INI fájlt és olyan függvényei voltak, hogy getString, getInt és getBool. Asszem a Delphi INI olvasója is valahogy így működött anno, amikor játszottam vele. :D
3

olvasás? ;)

Hodicska Gergely · 2006. Júl. 6. (Cs), 00.39
Egy kis logikai buktatót érzek a megközelítésedben: hogyan fogod olvasni a konfigot? ;)
Amúgy jó kis kérdés, egy lehetséges megoldás:
<?php
	class config
	{
		var $_CFG = null;

		function config($CFG)
		{
			$this->_CFG = $CFG;
		}

		function getVar($path)
		{
			$path = explode('.', $path);
			return $this->_getVar($path, $this->_CFG, count($path));
		}

		function _getVar($path, &$array, $level)
		{
			if ($level > 1) {
				if (!isset($array[$path[0]])) {
					return null;
				} else {
					return $this->_getVar(array_slice($path, 1), $array[$path[0]], $level-1);
				}
			} else {
				if (isset($array[$path[0]])) {
					return $array[$path[0]];
				} else {
					return null;
				}
			}
		}

		function setVar($path, $value)
		{
			$path = explode('.', $path);
			$this->_setVar($path, $value, $this->_CFG, count($path));
		}

		function _setVar($path, $value, &$array, $level)
		{
			if ($level > 1) {
				if (!is_array($array)) {
					$array = array();
				}
				if (!isset($array[$path[0]])) {
					$array[$path[0]] = array();
				}
				$this->_setVar(array_slice($path, 1), $value, $array[$path[0]], $level-1);
			} else {
				$array[$path[0]] = $value;
			}
		}
	}

	$config = new config(array(
		'db' => array(
			'user' => 'foo',
			'pass' => 'foo',
			'name' => 'foo',
		),
	));

	$config->setVar('db.user.new.bar', 5);
	echo '<pre>'.htmlentities(print_r($config->getVar('db'), true)).'</pre>';
	echo '<pre>'.htmlentities(print_r($config->getVar('db.user'), true)).'</pre>';
	echo '<pre>'.htmlentities(print_r($config->getVar('db.user.new'), true)).'</pre>';
	echo '<pre>'.htmlentities(print_r($config->getVar('db.user.new.bar'), true)).'</pre>';
?>
Felhő
6

Köszönöm, elegáns megoldás!

Dualon · 2006. Júl. 6. (Cs), 11.20
Nagyon szép, elegáns megoldás!
Már hajnali háromtól legóztam vele, szétszedtem, átépítettem, meg vissza, és nagyon tetszik. Remek a rekurzív útvonal-fogyasztás.
Nem bánod, ha használom a kódod (saját célra), ugye? Beleírom a forráskódba a köszönetnyilvánítást.

Érdekes, hogy a pontozott útvonal nekem is eszembe jutott, aztán a beszélt nyelv "ebből ez következik" kettőspontjára váltottam. Megkérdezhetem, hogy miért ezt választottad? OO JS cikked kapcsolatban van ezzel? :)

Egy kis logikai buktatót érzek a megközelítésedben: hogyan fogod olvasni a konfigot? ;)


Erre gondolsz?

// az egesz egy felteteles blokkban
$var = $CFG;
if ($s_var_path!=='') {
	foreach($a_cfg_nodes as $node) {
		$var = $var[$node];
	}
}			
		
return $var; // node erteke, v. ha path ures, akkor teljes CFG tomb
Ez a része volt szvsz a könnyebb.
8

szivesen

Hodicska Gergely · 2006. Júl. 6. (Cs), 11.46
Nagyon szép, elegáns megoldás!

köszi

Nem bánod, ha használom a kódod (saját célra), ugye?

Nyugodtan, Neked írtam, kis éjfél utáni levezetés. :)

Érdekelt a dolog, mert előjött már nekem is hasonló probléma (Request objekt tudjon olyat, hogy $request->get("user[name]")), csak ott kicsit bonyolultabb megoldásszületett (korrigálni kell ilyen esetben a $FILES tömben lévő elkefélt tartalmat).

Érdekes, hogy a pontozott útvonal nekem is eszembe jutott, aztán a beszélt nyelv "ebből ez következik" kettőspontjára váltottam. Megkérdezhetem, hogy miért ezt választottad? OO JS cikked kapcsolatban van ezzel? :)

Nem volt benne semmi ilyen tudatosság, csak úgy ez jött.

logikai buktató

Arra gondoltam, hogy ha van egy set függvényed és abban van a konfig egy statikus tömbben, akkor hogyan csinálsz get függvényt?


Felhő
9

logikai buktató

Dualon · 2006. Júl. 6. (Cs), 12.29
Arra gondoltam, hogy ha van egy set függvényed és abban van a konfig egy statikus tömbben, akkor hogyan csinálsz get függvényt?


Eredetileg egyetlen cfg() függvény végezte a set és get feladatot is (nyitóbejegyzésem kódrészletében benn is maradt a // CFG SET/GET megjegyzés). Ha volt változóérték, akkor set, egyébként get. Működött.

Utóbb azonban rájöttem, hogy ez inkább tervezési hiba, mint feature :), mert ha null-t adok változóértéknek (~unset), akkor a függvény get-ként működik.

Végeredményben tehát valóban volt logikai hiba, csak nem ott.

A kódot pedig még egyszer köszönöm!
4

Hát én ezt a topicot...

-zsolti- · 2006. Júl. 6. (Cs), 00.50
...kinyomtatom, és megy a faliújságra. Még több ilyet.
7

Az eredeti amúgy miért nem működött?

Dualon · 2006. Júl. 6. (Cs), 11.23
A megoldás Felhő jóvoltából megszületett, viszont még mindig nem jöttem rá, az eredeti megközelítés miért nem működött. Valakinek esetleg van ötlete? (Ez már csak a kíváncsiság, ne öljetek bele túl sok energiát...)