I'm writing a text tag parser and I'm currently using this recursive method to create tags of n words. Is there a way that it can be done non-recursively or at least be optimized? Assume that $this->dataArray could be a very large array.
/**
* A recursive function to add phrases to the tagTracker array
* #param string $data
* #param int $currentIndex
* #param int $depth
*/
protected function compilePhrase($data, $currentIndex, $depth){
if (!empty($data)){
if ($depth >= $this->phraseStart){
$this->addDataCount($data, $depth);
}
if ($depth < $this->phraseDepth){
$currentIndex = $currentIndex + 1;
//$this->dataArray is an array containing all words in the text
$data .= ' '.$this->dataArray[$currentIndex];
$depth += 1;
$this->compilePhrase($data, $currentIndex, $depth);
}
}
}
See if you can use tail recursion rather than call-based recursion. Some rewriting may be required but a cursory looks says it is fine to do.
Tail recursion is great for a subset of recursive functions, and good practice to spot when loops can replace recursion, and how to rewrite.
Saying that, I don't know what the overhead inside PHP is of the call. Might just be one return-pointer type setup rather than a real stack wind.
Turns out about the same. Does PHP optimize tail recursive calls out itself?
Here is my rewrite, but beware, my brain is currently sleep deprived!
protected function compilePhrase($data, $currentIndex, $depth){
/* Loop until break condition */
while(true) {
if (!empty($data)){
if ($depth >= $this->phraseStart){
$this->addDataCount($data, $depth);
}
if ($depth < $this->phraseDepth){
$currentIndex = $currentIndex + 1;
// A test here might be better than the !empty($data)
// in the IF condition. Check array bounds, assuming
// array is not threaded or anything
$data .= ' '.$this->dataArray[$currentIndex];
$depth += 1;
}else{
break;
}
}else{
break;
}
}
/* Finish up here */
return($this->dataArray);
}
Related
From a database I am getting a text where the function htmlentities() was applied four times. Sample text:
specials &amp; workshops
In order to decode this text I have to do the following:
$out = html_entity_decode(html_entity_decode(html_entity_decode(html_entity_decode("specials &amp;amp; workshops"))));
Result:
specials & workshops
Is there a natural way in PHP to write this more efficient?
I like to do it recursively in such a way that I do not need to know how many entities to match.
$string = 'specials &amp;amp; workshops';
$entity = '/&/';
function recurseHTMLDecode($str, $entity) {
preg_match($entity, $str, $matches);
echo count($matches);
if(1 == count($matches)) {
$str = html_entity_decode($str);
$str = recurseHTMLDecode($str, $entity);
return $str;
} else {
return $str;
}
}
var_dump(recurseHTMLDecode($string, $entity));
This returns:
11110string(20) "specials & workshops"
Here is the EXAMPLE
This could be improved by adding a whitelist of entities to the function so you would not have to specify the entity when calling, just loop through the whitelist. This would solve the issue of having more than one entity in a string. It could be quite complex.
Why not declare a function to do so?
$in = "specials &amp; workshops";
$decode = function($in) {
foreach(range(1,4) as $x) $in = html_entity_decode($in); return $in; };
function decode($in) {
foreach(range(1,4) as $x)
$in = html_entity_decode($in);
return $in;
}
// inline
$out = $decode($in);
// traditional
$out = decode($in);
According to the recursive idea of #JayBlanchard I have no created the following - really like it:
/**
* Apply a function to a certain input multiple times.
*
* #param $input: The input variable:
* #param callable $func: The function to call.
* #param int $times: How often the function should be called. -1 for deep call (unknown number of calls required). CAUTION: If output always changes this results in an endless loop.
* #return mixed
*/
function recapply($input,callable $func,int $times) {
if($times > 1) {
return recapply($func($input),$func,$times - 1);
} else if($times == -1) {
$res = $func($input);
if($res === $input) {
return $input;
} else {
return recapply($res,$func,-1);
}
}
return $func($input);
}
Working example call:
echo recapply("specials &amp; workshops","html_entity_decode",4);
I use scrutinizer to analyse my code, and I get a function declared:
Worst rated PHP Operations
This is the function:
/**
* Insert Empty Fighters in an homogeneous way.
*
* #param Collection $fighters
* #param Collection $byeGroup
*
* #return Collection
*/
private function insertByes(Collection $fighters, Collection $byeGroup)
{
$bye = count($byeGroup) > 0 ? $byeGroup[0] : [];
$sizeFighters = count($fighters);
$sizeByeGroup = count($byeGroup);
$frequency = $sizeByeGroup != 0
? (int)floor($sizeFighters / $sizeByeGroup)
: -1;
// Create Copy of $competitors
$newFighters = new Collection();
$count = 0;
$byeCount = 0;
foreach ($fighters as $fighter) {
if ($frequency != -1 && $count % $frequency == 0 && $byeCount < $sizeByeGroup) {
$newFighters->push($bye);
$byeCount++;
}
$newFighters->push($fighter);
$count++;
}
return $newFighters;
}
What this function is doing is trying to insert Empty Fighters in a regular
/ homogeneous way
But for me, this method seems quite OK, what am I not seeing?
Any better way to achieve it???
Misleading name (probably not picked up by Scrutinizer). At no point the actual $byeGroup collection is necessary
private function insertByes(Collection $fighters, Collection $byeGroup)
An if statement, that is only used to pull out something, that should have been a method's parameter.
$bye = count($byeGroup) > 0 ? $byeGroup[0] : [];
$sizeFighters = count($fighters);
$sizeByeGroup = count($byeGroup);
Another if statement that adds to complexity. Also uses weak comparison.
$frequency = $sizeByeGroup != 0
? (int)floor($sizeFighters / $sizeByeGroup)
: -1;
// Create Copy of $competitors
$newFighters = new Collection();
$count = 0;
$byeCount = 0;
Content of this foreach should most likely go in a separate method.
foreach ($fighters as $fighter) {
And that complex condition in yet another if statement (which also contains weak comparison), should also be better in a well named private method.
if ($frequency != -1 && $count % $frequency == 0 && $byeCount < $sizeByeGroup) {
Since $bye can be an empty array, this kinda makes no sense.
$newFighters->push($bye);
$byeCount++;
}
$newFighters->push($fighter);
$count++;
}
return $newFighters;
}
TBH, I have no idea what this method does, and it would also be really hard to write any unit test for it.
I am trying to do a very simple but numerous iterations task. I choose 7 random serial numbers from an array of 324000 serial numbers and place them in another array and then search that array to see if a particular number is within it, execute another script and fwrite out how many times the looked for number is in the array.
This goes fairly fast in single thread. But when I put it in pthreads, even one single pthread running is 100x slower than single thread. The workers are not sharing any resources (i.e. the grab all info from their own folders and write info to their own folders)..fwrite bottlenecks is not the problem. The problem is with the arrays which I note below. Am I running into a cache line problem, where the arrays although they have separate variables are still sharing the same cache line? Sigh...much appreciate your help, in figuring out why the arrays are slowing it to a crawl.
<?php
class WorkerThreads extends Thread
{
private $workerId;
private $linesId;
private $linesId2;
private $c2_result;
private $traceId;
public function __construct($id,$newlines,$newlines2,$xxtrace)
{
$this->workerId = $id;
$this->linesId = (array) $newlines;
$this->linesId2 = (array) $newlines2;
$this->traceId = $xxtrace;
$this->c2_result= (array) array();
}
public function run()
{
for($h=0; $h<90; $h++) {
$fp42=fopen("/folder/".$this->workerId."/count.txt","w");
for($master=0; $master <200; $master++) {
// *******PROBLEM IS IN THE <3000 loop -very slow***********
$b=0;
for($a=0; $a<3000; $a++) {
$zex=0;
while($zex != 1) {
$this->c2_result[0]=$this->linesId[rand(0,324631)];
$this->c2_result[1]=$this->linesId[rand(0,324631)];
$this->c2_result[2]=$this->linesId[rand(0,324631)];
$this->c2_result[3]=$this->linesId[rand(0,324631)];
$this->c2_result[4]=$this->linesId[rand(0,324631)];
$this->c2_result[5]=$this->linesId[rand(0,324631)];
$this->c2_result[6]=$this->linesId[rand(0,324631)];
if(count(array_flip($this->c2_result)) != count($this->c2_result)) { //echo "duplicates\n";
$zex=0;
} else { //echo "no duplicates\n";
$zex=1;
//exit;
}
}
// *********PROBLEM here too !in_array statement, slowing down******
if(!in_array($this->linesId2[$this->traceId],$this->c2_result)) {
//fwrite($fp4,"nothere\n");
$b++;
}
}
fwrite($fp42,$b."\n");
}
fclose($fp42);
$mainfile3="/folder/".$this->workerId."/count_pthread.php";
$command="php $mainfile3 $this->workerId";
exec($command);
}
}
}
$xxTrack=0;
$lines = range(0, 324631);
for($x=0; $x<56; $x++) {
$workers = [];
// Initialize and start the threads
foreach (range(0, 8) as $i) {
$workers[$i] = new WorkerThreads($i,$lines,$lines2,$xxTrack);
$workers[$i]->start();
$xxTrack++;
}
// Let the threads come back
foreach (range(0, 8) as $i) {
$workers[$i]->join();
}
unset($workers);
}
UPDATED CODE
I was able to speed up the original code by 6x times with help from #tpunt suggestions. Most importantly what I learned is that the code is being slowed down by the calls to rand(). If I could get rid of that, then speed time would be 100x faster. array_rand,mt_rand() and shuffle() are even slower. Here is the new code:
class WorkerThreads extends Thread
{
private $workerId;
private $c2_result;
private $traceId;
private $myArray;
private $myArray2;
public function __construct($id,$xxtrace)
{
$this->workerId = $id;
$this->traceId = $xxtrace;
$c2_result=array();
}
public function run()
{
////////////////////THE WORK TO BE DONE/////////////////////////
$lines = file("/fold/considers.txt",FILE_IGNORE_NEW_LINES);
$lines2= file("/fold/considers.txt",FILE_IGNORE_NEW_LINES);
shuffle($lines2);
$fp42=fopen("/fold/".$this->workerId."/count.txt","w");
for($h=0; $h<90; $h++) {
fseek($fp42, 0);
for($master=0; $master <200; $master++) {
$b=0;
for($a=0; $a<3000; $a++) {
$zex=0;
$myArray = [];
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
while (count($myArray) !== 7) {
$myArray[rand(0,324631)] = true;
}
if (!isset($myArray[$lines2[$this->traceId]])) {
$b++;
}
}
fwrite($fp42,$b."\n");
}
$mainfile3="/newfolder/".$this->workerId."/pthread.php";
$command="php $mainfile3 $this->workerId";
exec($command);
}//END OF H LOOP
fclose($fp42);
}
}
$xxTrack=0;
$p = new Pool(5);
for($b=0; $b<56; $b++) {
$tasks[$b]= new WorkerThreads($b,$xxTrack);
$xxTrack++;
}
// Add tasks to pool queue
foreach ($tasks as $task) {
$p->submit($task);
}
// shutdown will wait for current queue to be completed
$p->shutdown();
Your code is just incredibly inefficient. There are also a number of problems with it - I've made a quick breakdown of some of these things below.
Firstly, you are spinning up over 500 threads (9 * 56 = 504). This is going to be very slow because threading in PHP requires a shared-nothing architecture. This means that a new instance of PHP's interpreter will need to be created for each thread you create, where all classes, interfaces, traits, functions, etc, will need to be copied over to the new interpreter instance.
Perhaps more to the point, though, is that your 3 nested for loops are performing 54 million iterations (90 * 200 * 3000). Multiply this by the 504 threads being created, and you can soon see why things are becoming sluggish. Instead, use a thread pool (see pthreads' Pool class) with a more modest amount of threads (try 8, and go from there), and cut down on the iterations being performed per thread.
Secondly, you are opening up a file 90 times per thread (so a total of 90 * 504 = 45360). You only need one file handler per thread.
Thirdly, utilising actual PHP arrays inside of Threaded objects makes them read-only. So with respect to the $this->c2_result property, the code inside of your nested while loop should not even work. Not to mention that the following check does not look for duplicates:
if(count(array_flip($this->c2_result)) != count($this->c2_result))
If you avoid casting the $this->c2_result property to an array (therefore making it a Volatile object), then the following code could instead replace your while loop:
$keys = array_rand($this->linesId, 7);
for ($i = 0; $i < 7; ++$i) {
$this->c2_result[$this->linesId[$keys[$i]]] = true;
}
By setting the values as the keys in $this->c2_result we can remove the subsequent in_array function call to search through the $this->c2_result. This is done by utilising a PHP array as a hash table, where the lookup time for a key is constant time (O(1)), rather than linear time required when searching for values (with in_array). This enables us to replace the following slow check:
if(!in_array($this->linesId2[$this->traceId],$this->c2_result))
with the following fast check:
if (!isset($this->c2_result[$this->linesId2[$this->traceId]]))
But with that said, you don't seem to be using the $this->c2_result property anywhere else. So (assuming you haven't purposefully redacted code that uses it), you could remove it altogether and simply replace the while loop at check after it with the following:
$found = false;
foreach (array_rand($this->linesId, 7) as $key) {
if ($this->linesId[$key] === $this->linesId2[$this->traceId]) {
$found = true;
break;
}
}
if (!$found) {
++$b;
}
Beyond the above, you could also look at storing the data you're collecting in-memory (as some property on the Threaded object), to prevent expensive disk writes. The results could be aggregated at the end, before shutting down the pool.
Update based up your update
You've said that the rand function is causing major slowdown. Whilst it may be part of the problem, I believe it is actually all of the code inside of your third nested for loop. The code inside there is very hot code, because it gets executed 54 million times. I suggested above that you replace the following code:
$zex=0;
while($zex != 1) {
$c2_result[0]=$lines[rand(0,324631)];
$c2_result[1]=$lines[rand(0,324631)];
$c2_result[2]=$lines[rand(0,324631)];
$c2_result[3]=$lines[rand(0,324631)];
$c2_result[4]=$lines[rand(0,324631)];
$c2_result[5]=$lines[rand(0,324631)];
$c2_result[6]=$lines[rand(0,324631)];
$myArray = (array) $c2_result;
$myArray2 = (array) $c2_result;
$myArray=array_flip($myArray);
if(count($myArray) != count($c2_result)) {//echo "duplicates\n";
$zex=0;
} else {//echo "no duplicates\n";
$zex=1;
//exit;
}
}
if(!in_array($lines2[$this->traceId],$myArray2)) {
$b++;
}
with a combination of array_rand and foreach. Upon some initial tests, it turns out that array_rand really is outstandingly slow. But my hash table solution to replace the in_array invocation still holds true. By leveraging a PHP array as a hash table (basically, store values as keys), we get a constant time lookup performance (O(1)), as opposed to a linear time lookup (O(n)).
Try replacing the above code with the following:
$myArray = [];
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
$myArray[rand(0,324631)] = true;
while (count($myArray) !== 7) {
$myArray[rand(0,324631)] = true;
}
if (!isset($myArray[$lines2[$this->traceId]])) {
$b++;
}
For me, this resulted in a 120% speedup.
As for further performance, you can (as mentioned above, again) store the results in-memory (as a simple property) and perform a write of all results at the end of the run method.
Also, the garbage collector for pthreads is not deterministic. It should therefore not be used to retrieve data. Instead, a Threaded object should be injected into the worker thread, where data to be collected should be saved to this object. Lastly, you should shutdown the pool after garbage collection (which, again, should not be used in your case).
despite it is unclear about your code and what $newlines and $newlines2 are, so, I am just guessing here...
something like this ?
The idea is to avoid as much as possible fopen and fwrite in your loop.
1 - open it only once in the construct.
2 - concat your chain in your loop.
3 - write it only once after the loop.
class WorkerThreads extends Thread {
private $workerId;
private $linesId;
private $linesId2;
private $c2_result;
private $traceId;
private $fp42;
private $mainfile3;
public function __construct($id, $newlines, $newlines2, $xxtrace) {
$this->workerId = $id;
$this->linesId = (array) $newlines;
$this->linesId2 = (array) $newlines2;
$this->traceId = $xxtrace;
$this->c2_result = array();
$this->fp42 = fopen("/folder/" . $id . "/count.txt", "w");
$this->mainfile3 = "/folder/" . $id . "/count_pthread.php";
}
public function run() {
for ($h = 0; $h < 90; $h++) {
$globalf42='';
for ($master = 0; $master < 200; $master++) {//<200
$b = 0;
for ($a = 0; $a < 3000; $a++) {
$zex = 0;
if ($zex != 1) {
for ($ii = 0; $ii < 6; $ii++) {
$this->c2_result[$ii] = $this->linesId[rand(0, 324631)];
}
$zex = (count(array_flip($this->c2_result)) != count($this->c2_result)) ? 0 : 1;
}
if (!in_array($this->linesId2[$this->traceId], $this->c2_result)) {
$b++;
}
}
$globalf42 .= $b . "\n";
}
fwrite($this->fp42, $globalf42);
fclose($this->fp42);
$command = "php $this->mainfile3 $this->workerId";
exec($command);
}
}
}
I'm trying to count how many numbers inside of a variable. Here is the regex that i use..
preg_match('/[^0-9]/', $password, $numbers, PREG_OFFSET_CAPTURE);
When I try to get all numbers one by one, I use:
print_r($this->filter->password_filter($data["user_password"]));
user_password is 123d4sd6789. Result is an empty array.
Array ( )
Well, you can easily do it using preg_split:
$temp = preg_split('/\d/', $password);
$numCount = count($temp) - 1;
Your regex is flawed, since you're trying to count the number of digits in a password, using:
/[^0-9]/
Won't cut it, perhpas you meant to write:
/[0-9]/
Because what you have now matches everything EXCEPT a number.
There are a great number of ways to do what you're trying to do, I've benchmarked 4 different approaches, and found that using regex is the fastest approach. Using the bundled pcre extension that PHP ships with, preg_split outperforms all other approaches ~70% of the time, 20% of the time, the loops are faster, though, and ~10% preg_match_all is fastest.
On codepad, who don't use the standard PCRE for some reason, preg_match_all doesn't work, nor did shuffle prove to be reliable, so I added a knuth method, and I decided to test the differences between /\d/ and /[0-9]/ in combination with preg_split instead. On codepad, regex is faster >95% of the time as a result.
In short: use preg_split + regex for the best results.
Anyway, here's the benchmark code. It may seem silly to put it all into a class, but really, it's the fair way to benchmark. The string that is processed is kept in memory, as are all the arrays that are used to time the functions, and compare speeds.
I'm not calling the test methods directly, either, but use a timeCall method instead, simply because I want the garbage collector to GC what needs to be GC'ed after each call. Anyway, it's not too difficult to figure this code out, and it's the results that matter
class Bench
{
/**
* #var string
*/
private $str = '123d4sd6789';
private $functions = array(
'regex' => null,
'regex2' => null,
'loop' => null,
'loop2' => null
);
private $random = null;
public function __construct()
{
$this->random = array_keys($this->functions);
if (!shuffle($this->random)) $this->knuth();
}
/**
* Knuth shuffle
*/
private function knuth()
{
for ($i=count($this->random)-1,$j=mt_rand(0,$i);$i>0;$j=mt_rand(0,--$i))
{
$temp = $this->random[$j];
$this->random[$j] = $this->random[$i];
$this->random[$i] = $temp;
}
}
/**
* Call all functions in random order, timing each function
* determine fastest approach, and echo results
* #param $randomize
* #return string
*/
public function test($randomize)
{
if ($randomize) if (!shuffle($this->random)) $this->knuth();
foreach($this->random as $func) $this->functions[$func] = $this->timeCall($func);
$fastest = array('f', 100000);
foreach($this->functions as $func => $time)
{
$fastest = $fastest[1] > $time ? array($func, $time) : $fastest;
echo 'Function ', $func, ' took ', $time, 'ms', PHP_EOL;
}
echo 'Fastest approach: ', $fastest[0], ' (', $fastest[1], 'ms)', PHP_EOL;
return $fastest[0];
}
/**
* Time function call
* #param string $func
* #return float mixed
*/
private function timeCall($func)
{
echo $func, PHP_EOL;
$start = microtime(true);
$this->{$func}();
return (microtime(true) - $start);
}
/**
* Count digits in string using preg_split
* #return int
*/
private function regex()
{
return count(preg_split('/\d/', $this->str)) - 1;
}
/**
* count digits in string using str_split + is_numeric + loop
* #return int
*/
private function loop()
{
$chars = str_split($this->str);
$counter = 0;
foreach($chars as $char) if (is_numeric($char)) ++$counter;
return $counter;
}
/**
* count digits by iterating over string, using is_numeric
* #return int
*/
private function loop2()
{
for($i=0,$j=strlen($this->str),$counter=0;$i<$j;++$i) if (is_numeric($this->str{$i})) ++$counter;
return $counter;
}
/**
* use preg_split + [0-9] instead of \d
* #return int
*/
private function regex2()
{
return count(preg_split('/[0-9]/', $this->str)) - 1;
if (preg_match_all('/[0-9]/',$this->str, $matches)) return count($matches);
return 0;
}
}
$benchmark = new Bench();
$totals = array();
for($i=0;$i<10;++$i)
{
$func = $benchmark->test($i);
if (!isset($totals[$func])) $totals[$func] = 0;
++$totals[$func];
if ($i < 9) echo PHP_EOL, '---------------------------------------------', PHP_EOL;
}
var_dump($totals);
Here's the codepad I set up
Do you really want a regex?
$arr1 = str_split($password);
$counter=0;
foreach($arr1 as $v){
if(is_numeric($v))$counter++;
}
Use preg_match_all to select all the numbers:
$reg = '/[0-9]/';
$string = '123d4sd6789';
preg_match_all($reg, $string, $out);
echo (count($out[0]));
I need to do fast lookups to find if an array exists in an array. If I knew the depth of the array It would be easy - and fast!
$heystack['lev1']['lev2']['lev3'] = 10; // $heystack stores 10,000s of arrays like this
if(isset($heystack[$var1][$var2][$var3])) do something...
How would you do this dynamically if you don't know the depth? looping and searching at each level will be too slow for my application.
Your question has already the answer:
if (isset($heystack[$var1][$var2][$var3]))
{
# do something...
}
If you don't know the how many $var1 ... $varN you have, you can only do it dynamically which involves either looping or eval and depends if you need to deal with string or numerical keys. This has been already asked and answered:
Loop and Eval: use strings to access (potentially large) multidimensional arrays (and that's only one of the many)
If you are concerned about speed, e.g. if the array is always the same but you need to query it often, create a index first that has compound keys so you can more easily query it. That could be either done by storing all keys while traversing the array recursively:
class CompoundKeys extends RecursiveIteratorIterator
{
private $keys;
private $separator;
public function __construct($separator, RecursiveIterator $iterator, $mode = RecursiveIteratorIterator::SELF_FIRST, $flags = 0)
{
$this->separator = $separator;
parent::__construct($iterator, $mode, $flags);
}
public function current()
{
$current = parent::current();
if (is_array($current))
{
$current = array_keys($current);
}
return $current;
}
public function key()
{
$depth = $this->getDepth();
$this->keys[$depth] = parent::key();
return implode('.', array_slice($this->keys, 0, $depth+1));
}
}
Usage:
$it = new CompoundKeys('.', new RecursiveArrayIterator($array));
$compound = iterator_to_array($it, 1);
isset($compound["$var1.$var2.$var3"]);
Alternatively this can be done by traversing recursively and referencing the original arrays values:
/**
* create an array of compound array keys aliasing the non-array values
* of the original array.
*
* #param string $separator
* #param array $array
* #return array
*/
function array_compound_key_alias(array &$array, $separator = '.')
{
$index = array();
foreach($array as $key => &$value)
{
if (is_string($key) && FALSE !== strpos($key, $separator))
{
throw new InvalidArgumentException(sprintf('Array contains key ("%s") with separator ("%s").', $key, $separator));
}
if (is_array($value))
{
$subindex = array_compound_key_alias($value, $separator);
foreach($subindex as $subkey => &$subvalue)
{
$index[$key.$separator.$subkey] = &$subvalue;
}
}
else
{
$index[$key] = &$value;
}
}
return $index;
}
Usage:
$index = array_compound_key_alias($array);
isset($index["$var1.$var2.$var3"]);
You'll need some sort of looping but you won't need to traverse the entire depth. You can simply use a function that does the equivalent of $heystack[$var1][$var2][$var3], but dynamically:
$heystack['lev1']['lev2']['lev3'] = 10;
echo getElement($heystack, array('lev1', 'lev2', 'lev3')); // you could build second parameter dynamically
function getElement($array, $indexes = array())
{
foreach ($indexes as $index) {
$array = $array[$index];
}
return $array;
}
// output: 10
You'll need to put in some defense mechanisms to make the function more robust (for elements/indexes that don't exist) but this is the basic approach.