10

Here is my question: I am trying to create a random bar code for my application. I want to check that if that code is already in the column, then generate a new number. Check it again. If it's unique, return it to the caller, else generate again.

I am using a recursive function for this purpose. I have added numbers 1,2,3,4 inside my database so every time it runs. It has to show me 5,6,7,8,9 or 10.

Here is my function:

function generate_barcode(){
    $barcode = rand(1,10);
    $bquery = mysql_num_rows(mysql_query("SELECT * FROM stock_item WHERE barcode='$barcode'"));
    if($bquery==1){
        generate_barcode();
    }else{
        return $barcode;    
    }
 }

And I just tested it like this:

 $a = generate_barcode();
 if(isset($a))
 {
   echo $a;
 }
 else
 {
  echo 'Not Set';
 }  

So the problem is that it is sometimes showing me "Not Set", but I want it to always generate a unique number. I am not inserting the data, so it's not a problem that all of the numbers are reserved.

Someone just guide me and let me know what is wrong with the code. I can use other approaches to do that, but I need to know what is wrong with the supplied code.

ouflak
  • 2,458
  • 10
  • 44
  • 49
codegeek
  • 181
  • 1
  • 2
  • 9
  • 1
    Deprecated mysql* [Please, don't use mysql_* functions in new code.](http://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php) They are no longer maintained and are officially deprecated. Use mysqli or PDO – PHPhil Jul 25 '15 at 08:03
  • @PHPhil using shared hosting that supports only mysql – codegeek Jul 25 '15 at 08:05
  • Anyway you can do away with the `if($bquery==1)` because `if($bquery)` is a smidgen better. – ArtisticPhoenix Jul 25 '15 at 08:24
  • This question (and its accepted answer) is being discussed on [meta](https://meta.stackoverflow.com/questions/418239/seeking-canonical-non-returning-php-recursion#418241). – ouflak May 23 '22 at 10:17
  • As a result of the discussion on [meta](https://meta.stackoverflow.com/q/418239/9473764) this Q&A has been nominated as the defacto canonical for questions relating to the issue of failing to return the value from a recursive call. – Nick May 29 '22 at 01:06

4 Answers4

27

You need to return the generated number from your recursive call too, like:

function generate_barcode() {
  $barcode = rand(1, 10);
  $bquery = mysql_num_rows(mysql_query("SELECT * FROM stock_item WHERE barcode='$barcode'"));
  if ($bquery == 1) {
    return generate_barcode(); // changed!
  }
  else {
    return $barcode;
  }
}

(You should include some kind of exit for the case that all numbers are 'taken'. This current version will call itself recursively until the PHP recursion limit is reached and will then throw an error.)

ouflak
  • 2,458
  • 10
  • 44
  • 49
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43
  • 8
    Hey @hek2mgl, OP already admitted that the approach chosen was 'not the best one' and there *has* already been a discussion on this being recursive - see above. He simply wanted to know why his code didn't work. So there is no reason for you being abusive here. – Carsten Massmann Jul 25 '15 at 09:08
  • 1
    To be true, any recursive algorithm can be replaced by an iterative one - also meaning, any iterative algorithm can be replaced by a recursive one. So when I'm saying *this is not a recursive algorithm* I was not fully right. Of course you can solve it with a recursive algorithm - as you've shown. However, when reading the question I was confused why the OP tries to solve the problem the recursive way. This makes no sense IMHO and is contra-productive. Beside that, it is obvious that this algorithm, regardless of it is written in a recursive or iterative way would not solve the problem. – hek2mgl Jul 25 '15 at 11:37
  • Sure the actual question needs answering, but this is a learning platform, and so it's welcomed to offer good advice in addition to answering the question. "This is the answer to your question... however I suggest you do this instead" – James Jul 15 '22 at 13:42
8

A return statement passes a value back to the immediate caller of the current function's call-frame. In the case of recursion, this immediate caller can be another invocation of that same function.

You can counter this by doing the following:

Change:

generate_barcode();

to:

return generate_barcode();
PHPhil
  • 1,555
  • 13
  • 27
0

Do it like this:

$hash = md5( microtime().rand(0, 1000) );

Adding a time component means it will pretty much be unique. Unless you have like 32^32 of them.

If it has to be just numbers, just use the pkey and add like 10000 on to it for looks. or such.

After careful analysis - there is nothing wrong with it, but:

$a = generate_barcode();
if(isset($a))  <<< this bit

See you return the unique value and then you say it's isset my unique value, and $a will always be set, because if it's not you recurse the function until it is, and then you return it. Therefore it is always set...

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ArtisticPhoenix
  • 21,464
  • 2
  • 24
  • 38
0

You are trying to do:

while(true) {
    $barcode = rand(1,10);
    $bquery = mysql_num_rows(mysql_query("SELECT * FROM stock_item WHERE barcode='$barcode'"));
    if($bquery===0){
        break;
    }
}

echo $barcode;

However, this will obviously only work for 10 bar codes and leading to an endless loop after that - meaning it is not the right approach to create a large number of bar codes.

Instead I would suggest to use an auto_increment to generate the bar code.

Btw, the mysql extension is deprecated. Use mysqli or PDO for new code.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
hek2mgl
  • 152,036
  • 28
  • 249
  • 266