PHP recursive function not allowing page to load

200 views Asked by At

I am trying to display the total number in each line of a file that does not contain a path to another file as well as the filename, but if it has a path to another file loop through that file and sum all the number it has and the loop goes on and on as long as there exists a path to a file in the current file.

here is my code

function fileProcessor($value){
    if(file_exists(trim($value))){
        $total = 0;
        $files = file($value, FILE_SKIP_EMPTY_LINES);
        foreach($files as $data) {
            if(!preg_match("/.txt/i", $data)){
                $num = floatval($data);
                $total += $num;
            } else {
                fileProcessor(trim($data));
            }
        }
        echo $value. ' -  ' .($total);
    } else {
        echo 'File does not exist';
    }

    fileProcessor('text_files/first.txt');
}

I have 3 .txt files I'm working with, inside those files I have something like this

first.txt


  • 1
  • 3
  • 3
  • second.txt

second.txt


  • 2
  • 3
  • third.txt

third.txt


  • 1
  • 2

The output I am looking for


  • first.txt - 15
  • second.txt - 8
  • third.txt - 3

I will really appreciate it if someone can point me in the right direction, I don't know if I'm doing it right.

2

There are 2 answers

6
Tangentially Perpendicular On BEST ANSWER

There are two problems with your code:

  • You're not including the directory for the source file in the path to subsidiary files, so those files are never found.
  • You're not returning the total from the function so that higher level invocations can add the total for subsidiary files

Correcting those issues, and renaming the variables to something meaningful gives this code:

function fileProcessor($filename){
    if(file_exists(trim($filename))){
        $total = 0;
        $rows = file($filename, FILE_SKIP_EMPTY_LINES);
        foreach($rows as $data) {
            if(!preg_match("/.txt/i", $data)){
                $num = floatval($data);
                $total += $num;
            }else {
                $total += fileProcessor(dirname($filename)."/".trim($data));
            }
        }
        echo $filename. ' -  ' .($total)."<br>\n";
    }else{
        echo "File does not exist<br>\n";
    }
    return $total;
}

fileProcessor('text_files/first.txt');

Output:

text_files/third.txt - 3
text_files/second.txt - 8
text_files/first.txt - 15

This lists the files in the order in which the totals are finally accumulated, so the lowest levels appear first.

[Edit] I spotted a problem with the order of results if two or more filenames appear in a file. Here's a reworked version that deals with that.

To list the files in the order in which they are encountered requires reversing the natural order. In the new version below I've placed the filenames in a $fileList array which is passed down by reference. Each new invocation of the function adds its results to the end of that array. Once processing is complete the array is displayed.

function fileProcessor( &$fileList){
    // Get the last filename in the array
    end($fileList);
    $filename = key($fileList);

    if(file_exists(trim($filename))){
        // Accumulate the values
        $fileList[$filename] = 0;
        $rows = file($filename, FILE_SKIP_EMPTY_LINES);
        foreach($rows as $data) {
            if(!preg_match("/.txt/i", $data)){
                $num = floatval($data);
                $fileList[$filename] += $num;
            }else {
                // Recursive call. Add the next filename to the array
                $fileList[dirname($filename)."/".trim($data)]=0;
                $fileList[$filename] += fileProcessor($fileList);
            }
        }
    } else {
        $fileList[$filename]=  "File does not exist: $filename";
    }

    // return the total for the file to add to the accumulator for the file above.
    return  $fileList[$filename];
}


// Place the initial file in the array
$results = ['text_files/first.txt' => 0];

// run the function
fileProcessor($results);

// display the results
foreach($results as $filename=>$total) {
    echo $filename.' - '.$total."<br>\n";
}

Output:

text_files/first.txt - 15
text_files/second.txt - 8
text_files/third.txt - 3
1
Artem On

You could use the static var:

<?php
function fileProcessor($value) {
    static $results = [];
    if (file_exists(trim($value))) {
        $results[$value] = 0;
        $files = file($value, FILE_SKIP_EMPTY_LINES);
        foreach($files as $data) {
            if (!preg_match("/.txt/i", $data)) {
                $num = floatval($data);
                $results[$value] += $num;
            } else {
                fileProcessor(trim($data));
            }
        }
    } else {
        echo 'File does not exist';
    }
    reset($results);
    if (key($results) != $value) {
        return;
    }
    foreach($results as $key => $value) {
        echo $key. ' -  ' .$value."\n";
    }
}

fileProcessor('text_files/first.txt');

Output:

text_files/first.txt -  7
text_files/second.txt -  5
text_files/third.txt -  3