Search code examples
phparrayssimplexml

Why is !in_array() not working correctly? or is my logic flawed?


Here is the basic logic of what I'm trying to do that doesn't seem to be working.

  1. Loop through an array of the alphabet
  2. For each letter, loop through XML and if the program name starts with the current letter, and the major is not already in the array of output, then output a link with some data from the XML
  3. Whenever the link is output add the major to the array of output so we don't output doubles

The problem is that even though the major is in the array the line:

if (!in_array($program->Program, $majors)) {

is always returning true, causing the doubles to be output.

Currently on the page, after every link it output I'm also outputting the entire array to visually confirm that the major exists in the array and when you get towards the bottom of the page for the major WBAN, in the first output you can look at the array above it and see that it doesn't exist in the array so it ouputs however, the very next link output is also WBAN and you can see in the array above it that it does already exist so the if should return false and not output it...

My logic must be flawed somewhere - I've tried moving the array_push all around and can't get it to work right - I need fresh eyes.

Also - correct me if I'm wrong, but the reason I can't just purge the duplicates from the XML is because the full XML nodes aren't duplicates - just the major is.

For example, here is the XML - only the Program and MajorDescription would be duplicated so the full XML node wouldn't be considered a duplicate?:

<ProgramList>
    <MajorDescription>WEB ANIMATION AND DESIGN</MajorDescription>
    <Program>WBAN</Program>
    <ProgramLocations>
        <ProgramLocation>
            <Campus>Barrie</Campus>
        </ProgramLocation>
    </ProgramLocations>
    <Term>201310</Term>
</ProgramList>

Full code:

<?php 
$majors = array();
foreach ($alphabet as $l){
    $upper = strtoupper($l);                            

    foreach ($listxml->ProgramList as $program) {
        $letter = substr($program->MajorDescription, 0, 1);
        if (strcasecmp($letter, $l) == 0) {
            $count1++;
            $noprograms = false;
        }                               
    }

    if ($count1 == 0) {
        echo "<div id='$l' class='letter noprograms'>"; 
    } else {
        echo "<div id='$l' class='letter'>";
    }                           

    echo "<h2>$upper</h2>";

    foreach ($listxml->ProgramList as $program) {                             
        $letter = substr($program->MajorDescription, 0, 1);                

        if (strcasecmp($letter, $l) == 0) { 

            foreach ($majors as $major){
                echo "<p>".$major."</p>";
            }                  
            //this is where the problem is - this is always coming back true even if the major is in the array 
            if (!in_array($program->Program, $majors)) {                                    
                echo "<a href='../program/?major=".$program->Program."' class='programLink'>".$program->Program." - ".strtoupper($program->MajorDescription)."</a> - <a target='_BLANK' href='http://www.ontariocolleges.ca/SearchResults/GEORGIAN/_/N-1z1419r?Ntt=".rawurlencode($program->MajorDescription)."&Ns1=Program_Title_SORT&Ns2=0&Qo=20&SearchWithin=on'>Apply Now</a><br />";                                                                                                           
                array_push($majors, $program->Program);
            }                                                                       
            $count++;                                   
        }                               
    }
    if ($count == 0) {
        echo "<em class='noprograms'>No Programs</em><br />";
    }
    echo "</div>";                      
    $count = 0;
    $count1 = 0;
}

if ($noprograms) {
    echo '<div id="noprograms"><em>No results. Try broadening the search filters.</em></div>';
}
?>

Solution

  • You have to cast the node to a string value:

    if (!in_array((string)$program->Program, $majors)) {
    

    And:

    array_push($majors, (string)$program->Program);
    

    It's one of those things you have to get used to while using SimpleXML; functions that implicitly cast variables to a string don't need this special treatment, but if you're really paranoid I would suggest casting everything ;-)

    For instance, substr() doesn't need the cast, because it expects the first argument to be a string anyway and it will cast it automatically.