Função PHP retornando 0 se estiver em loop [duplicado]

Aug 18 2020

Eu tenho uma função PHP simples que conta o número de um dígito específico em um inteiro

function countOccurrence($number, $digit){
    $result = 0; while ($number > 0){
        $lastDigit = $number % 10;
        if($lastDigit === $digit){
            $result++; } $number = ($number - $lastDigit)/10;
    }
    return $result;
}

Que funciona perfeitamente bem por conta própria [Testado com countOccurrence (1111, 1) e retornou 4]

Mas quando eu o uso em um loop para um intervalo de números, ele sempre retorna 0.

if (isset($_POST['submit'])){
    $startNum = $_POST['startNum'];
    $endNum = $_POST['endNum'];
    $findNum = $_POST['findNum'];
    $occur = 0; echo 'from ' . $startNum . ' to ' . $endNum . ' find how many times ' . $findNum . ' occurs';
    echo '<br>';

    $numRange = makeArray($startNum, $endNum); foreach ($numRange as $number){ $test = countOccurrence($number, $findNum);
        echo 'number: ' . $number . ' find: ' . $findNum . ' countOccurrence('.$number.', '.$findNum.'): ' . $test . '<br>'; } echo '<br>'; echo '<p>The digit ' . $findNum . ' occurred ' . $occur . ' times within the range</p>'; echo '<br>'; echo 'countOccurrence(1111, 1) = '; $test = countOccurrence(1111, 1);
    echo $test;
}

O resultado que obtenho disso é "número: 1 encontrar: 1 contagemOccurrence (1, 1): 0" e assim por diante

Não tenho certeza de onde está errado aqui, pois parece que está tudo bem quando eu testo a função manualmente

Edit: Aqui está meu código completo

<html lang="en">
    <head>
        <title>Number Counter</title>
        <link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
    </head>
    <body>
        <div class="container">
            <form id="form" class="form-group" action="" method="post">
                <div class="form-group">
                    <label for="startId">Start Num</label>
                    <input type="number" name="startNum" id="startId" class="form-control">
                </div>

                <div class="form-group">
                    <label for="endId">End Num</label>
                    <input type="number" name="endNum" id="endId" class="form-control">
                </div>

                <div class="form-group">
                    <label for="findId">Find Num</label>
                    <input type="number" name="findNum" id="findId" class="form-control">
                </div>

                <input type="submit" name="submit">
            </form>
        </div>
    <script src="bootstrap/js/jquery-3.5.1.min.js"></script>
    <script src="bootstrap/js/jquery.validate.min.js"></script>
    <script src="bootstrap/js/bootstrap.min.js"></script>
    <script src="validate.js"></script>
    </body>
</html>

<?php

function countOccurrence($number, $digit){ $result = 0;
    while ($number > 0){ $lastDigit = $number % 10; if($lastDigit === $digit){ $result++;
        }
        $number = ($number - $lastDigit)/10; } return $result;
}

function makeArray($startNum, $endNum){
    $numRange = array(); for($ctr = $startNum; $startNum <= $endNum; $startNum++){
        array_push($numRange, $startNum);
    }
    return $numRange; } if (isset($_POST['submit'])){
    $startNum = $_POST['startNum'];
    $endNum = $_POST['endNum'];
    $findNum = $_POST['findNum'];
    $occur = 0; echo 'from ' . $startNum . ' to ' . $endNum . ' find how many times ' . $findNum . ' occurs';
    echo '<br>';

    $numRange = makeArray($startNum, $endNum); foreach ($numRange as $number){ $test = countOccurrence($number, $findNum);
        echo 'number: ' . $number . ' find: ' . $findNum . ' countOccurrence('.$number.', '.$findNum.'): ' . $test . '<br>'; } echo '<br>'; echo '<p>The digit ' . $findNum . ' occurred ' . $occur . ' times within the range</p>'; echo '<br>'; echo 'countOccurrence(1111, 1) = '; $test = countOccurrence(1111, 1);
    echo $test;
}


Edit: Obrigado pelas respostas! Acabei analisando os valores $ _POST para int em vez disso para obter os valores esperados

    $startNum = (int) $_POST['startNum'];
    $endNum = (int) $_POST['endNum'];
    $findNum = (int) $_POST['findNum'];

Respostas

SirPilan Aug 18 2020 at 10:04
function countOccurrence($number, $digit){
    $result = 0; while ($number > 0){
        $lastDigit = $number % 10;
        if($lastDigit === $digit){ // <-- bug is here
            $result++; } $number = ($number - $lastDigit)/10;
    }
    return $result;
}

Como você está fazendo uma comparação estrita, esses valores nunca são iguais. Aqui está o porquê:

Quando você obtém dados de $ _POST, é sempre uma string. Então você está ligando countOccurrence(1111, '1')que retornará 0 :)

Como mencionei nos comentários, você pode substituir suas funções por estas:

  • substr_count ao invés de countOccurrence
  • range ao invés de makeArray

Caso queira manter suas funções. Converta sua entrada em um int antes de passá-la para sua função com intval .

informação adicional

Para evitar que isso aconteça no futuro. Dê uma olhada neste post . É um recurso relativamente novo do php, que foi introduzido para esse tipo de cenário.

TimBrownlaw Aug 18 2020 at 10:10

É aqui que está o seu pequeno bugbear ...

if($lastDigit === $digit){

O que você está esperando aqui é uma comparação por valor e por tipo (===).

Você pode verificar isso usando gettype ();

while ($number > 0) { $lastDigit = $number % 10; echo '$lastDigit is a '.gettype($lastDigit); echo ' $digit is a '.gettype($digit); echo '<br>'; if ($lastDigit === $digit) { $result++;
    }
    $number = ($number - $lastDigit) / 10;
}

Os valores de um POST são invariavelmente do tipo String. Então, como $ digit é uma string e $ lastDigit é um número (inteiro). O uso de === falhará porque eles não são do mesmo tipo.

Assim, como o PHP tem a capacidade de fazer typecast por conta própria ... alterar === para == funcionará. IE

if ($lastDigit == $digit) {

O PHP tentará converter o valor RHS para o Tipo LHS e então realizará a comparação.

Portanto, agora você está apenas fazendo uma comparação e o PHP está convertendo $ dígitos em um inteiro.

Uma forma mais segura é forçar a fundição. Portanto, você pode converter $ digit de uma string para um inteiro e usar o código existente.

function countOccurrence($number, $digit) { $result = 0;

    $digit = intval($digit); // Force $digit to be an integer while ($number > 0) {
        $lastDigit = $number % 10;
        echo '$lastDigit is a '.gettype($lastDigit);
        echo ' $digit is a '.gettype($digit);
        echo '<br>';
        if ($lastDigit === $digit) {
            $result++; } $number = ($number - $lastDigit) / 10;

        echo ' $number is a '.gettype($number);
    }

    return $result;
}

Portanto, a lição disso, ao usar ===, certifique-se de que seus tipos também sejam os mesmos.