Friday, 26 September 2014

PHP: another generator example: primes

Duncan has mused me again. He's reworking his Project Euler exercises that he'd previously done in CFML, and is now implementing in PHP. In yesterday's exercise he was looking at prime numbers: "Project Euler: problem 7 (PHP)". I thought there was scope for another exercise in using PHP generators in this for me (see previous: "PHP: generators").

So I've come up with this implementation:

// primes.php

function createPrimeSequence($length=-1)
    $primes = [];
    $potential = 1;
    while ($length==-1 || sizeof($primes) < $length) {
        $upperThreshold = sqrt($potential);
        foreach($primes as $prime){
            if ($prime > $upperThreshold){
            if ($potential % $prime == 0){
                continue 2;
        $primes[] = $potential;
        yield end($primes);

$primesSequence = createPrimeSequence();

for ($i=1; $i <= 20; $i++){
    echo $primesSequence->current() . " ";

echo "<hr>";
foreach(createPrimeSequence(10) as $prime){
    echo "$prime ";

The prime calculation logic is pedestrian so I'll ignore that, the new conceit here is that I've added a $length argument to define a... well... length to the sequence, rather than it just continuing forever, as it did in the Fibonacci example. This means I can use it directly in a foreach() loop.

Oh, this outputs:

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71

2 3 5 7 11 13 17 19 23 29

New stuff I learned whilst doing this:

  • how PHP emulates optional arguments by being able to specify a default. It seems one cannot have a truly optional argument though.
  • sqrt() is PHP's square root function.
  • Both break and continue can exit multiple levels of looping, by specifying a number of levels to exit from (default is 1). Here I use continue 2 to break out of the inner foreach() loop, but also jump out of the current iteration of the while() loop.
  • the $array[] syntax is shorthand for array_push($array)
  • end() returns the last entry in an array, differing from array_pop() as it leaves the array intact.
There's nothing earth-shattering here, but I was pleased with the result, and I've definitely warmed to the idea of generators.