Skip to content

Faster Autoloading With Zend Framework 2

2013 May 2
by Richard Knop

Standard autoloader that comes with Zend Framework 2 is not and ideal one to use in production environment. I would suggest using a classmap autoloader which is faster. Here is how it works. When installing dependencies specified in composer.json, use -o option in order to generate classmap file:

php composer.phar install -o

It will create a PHP file at vendor/composer/autoload_classmap.php path which contains a static array of all knows classes from dependencies (Zend Framework 2, Doctrine 2 etc) with namespaces and paths to files.

You should also autoload all your modules in the same way. Either do it manually – cd into module folder and generate the classmap file:

cd module/Foo
../../vendor/bin/classmap_generator.php -w

Or use ANT:

  1. <target name="classmapgenerator" description="">
  2.   <exec executable="php">
  3.    <arg value="${basedir}/vendor/zendframework/zendframework/bin/classmap_generator.php" />
  4.    <arg value="-w" />
  5.    <arg value="-l" />
  6.    <arg value="module/Foo" />
  7.   </exec>
  8.   <exec executable="php">
  9.    <arg value="${basedir}/vendor/zendframework/zendframework/bin/classmap_generator.php" />
  10.    <arg value="-w" />
  11.    <arg value="-l" />
  12.    <arg value="module/Bar" />
  13.   </exec>
  14.  </target>

Inside your Module.php, change getAutoloaderConfig() method to look like this:

  1. public function getAutoloaderConfig()
  2.     {
  3.         return array(
  4.             'Zend\Loader\ClassMapAutoloader' => array(
  5.                 __DIR__ . '/autoload_classmap.php',
  6.             ),
  7.         );
  8.     }

Finally, change your init_autoloader.php file:

  1. require_once __DIR__ . '/vendor/zendframework/zendframework/library/Zend/Loader/AutoloaderFactory.php';
  2. require_once __DIR__ . '/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php';
  3. Zend\Loader\AutoloaderFactory::factory(array(
  4.     'Zend\Loader\ClassMapAutoloader' => array(
  5.         'Composer' => __DIR__ . '/vendor/composer/autoload_classmap.php',
  6.     )
  7. ));

Done! I don’t have any benchmarks at the moment. If I will have more free time, I will run some benchmarks to see how much faster it is actually.

Select a radio button with Mink / Behat

2013 April 30
by Richard Knop

Either I am completely blind or I just haven’t found an out-of-box solution for selecting a radio button with Mink / Behat. I have written a simple step definition which does this for me. In order for it to work, you have to have the radio button input element wrapped by a label element. Use the label text as argument:

/**
  1.  * @When /^I check the "([^"]*)" radio button$/
  2. */
  3. public function iCheckTheRadioButton($labelText)
  4.     {
  5.     foreach ($this->getMainContext()->getSession()->getPage()->findAll('css', 'label') as $label) {
  6.         if ($labelText === $label->getText() && $label->has('css', 'input[type="radio"]')) {
  7.             $this->getMainContext()->fillField($label->find('css', 'input[type="radio"]')->getAttribute('name'), $label->find('css', 'input[type="radio"]')->getAttribute('value'));
  8.             return;
  9.         }
  10.     }
  11.     throw new \Exception('Radio button not found');
  12. }

Use it like this inside your feature:

When I check the "Enabled" radio button

Introduction to boto (Python interface to AWS)

2013 February 23
tags: ,
by Richard Knop

More and more companies are using cloud storage for their files these days. There are many cloud services you can choose from (Windows Azure, Ubuntu Cloud, Amazon Web Services etc). I have used mainly Amazon Web Services (AWS) so I will show you how to easily upload files to S3 and how to copy files on S3 to different locations from Python script.

The only thing you need is Python and boto which is a Python interface to AWS. You can install it via pip:

pip install boto

Before uploading files to S3 you need to know your access key and secret key which will be provided to you by Amazon. You also need to create a bucket which is something like a namespace or a directory on S3. Once you have your access key, secret key and you have created a bucket, it’s easy to upload files to it with boto.

  1. from boto.s3.connection import S3Connection
  2.  
  3. YOUR_ACCESS_KEY_ID = "MY_ACCESS_KEY"
  4. YOUR_SECRET_ACCESS_KEY = "MY_SECRET_KEY"
  5. BUCKET = "MY_COOL_BUCKET"
  6.  
  7. conn = S3Connection(YOUR_ACCESS_KEY_ID, YOUR_SECRET_ACCESS_KEY)
  8. bucket = conn.get_bucket(BUCKET)
  9.  
  10. files_to_upload = {
  11.     '/path/to/hello.txt': 'hello_on_s3.txt'
  12.     '/path/to/world.txt': 'world_on_s3.txt'
  13. }
  14. for file_to_upload, s3_destination in files_to_upload.iteritems():
  15.     key = bucket.new_key(s3_destination)
  16.     key.set_contents_from_filename(file_to_upload)
  17.     key.set_acl('public-read')

Next thing you might want to do is to copy a file already uploaded to S3 bucket to a different location. This is how you do it:

  1. from boto.s3.connection import S3Connection
  2.  
  3. YOUR_ACCESS_KEY_ID = "MY_ACCESS_KEY"
  4. YOUR_SECRET_ACCESS_KEY = "MY_SECRET_KEY"
  5. BUCKET = "MY_COOL_BUCKET"
  6.  
  7. conn = S3Connection(YOUR_ACCESS_KEY_ID, YOUR_SECRET_ACCESS_KEY)
  8. bucket = conn.get_bucket(BUCKET)
  9.  
  10. files_to_copy = {
  11.     'hello_on_s3.txt' => 'foo_on_s3.txt',
  12.     'world_on_s3.txt' => 'bar_on_s3.txt'
  13. }
  14. for file_to_copy, new_destination in files_to_copy.iteritems():
  15.     bucket.copy_key(
  16.         new_destination,
  17.         BUCKET,
  18.         file_to_copy
  19.     )

The above code will copy the files to a different location in the same bucket. You can also specify a different bucket as well.

There are much more things you can do with boto. This post was just an introduction. Feel free to read the full boto documentation.

Access entity manager in Zend Framework 2 unit tests

2012 September 25
by Richard Knop

In order to access the entity manager in your unit tests you will have to make your PHPUnit bootstrap file a little bit more complex. You will need to access the entity manager if you are using Doctrine module together with Zend Framework 2.

Here is what I have done:

  1. <?php
  2.  
  3. use Zend\ServiceManager\ServiceManager,
  4.     Zend\Mvc\Service\ServiceManagerConfig;
  5.  
  6. class Bootstrap
  7. {
  8.     static public $config;
  9.     static public $sm;
  10.     static public $em;
  11.  
  12.     static public function go()
  13.     {
  14.         chdir(dirname(__DIR__));
  15.         include __DIR__ . '/../init_autoloader.php';
  16.         self::$config = include 'config/application.config.php';
  17.         Zend\Mvc\Application::init(self::$config);
  18.         self::$sm = self::getServiceManager(self::$config);
  19.         self::$em = self::getEntityManager(self::$sm);
  20.     }
  21.  
  22.     static public function getServiceManager($config)
  23.     {
  24.         $serviceManager = new ServiceManager(new ServiceManagerConfig);
  25.         $serviceManager->setService('ApplicationConfig', $config);
  26.         $serviceManager->get('ModuleManager')->loadModules();
  27.         return $serviceManager;
  28.     }
  29.  
  30.     static public function getEntityManager($serviceManager)
  31.     {
  32.         return $serviceManager->get('doctrine.entitymanager.orm_default');
  33.     }
  34. }
  35.  
  36. Bootstrap::go();

And then in your unit tests you can access the entity manager simply by:

  1. Bootstrap:$em

That was quite easy actually.

How to unit test redirecting in Zend Framework 2

2012 September 25
by Richard Knop

I’ve been working with Zend Framework 2 last couple of weeks and so far I like it better than the legacy Zend Framework. Proper namespaces and separate bootstrap for each module are nice features. I am still learning all the new features so I will be documenting some helpful ideas.

One problem I had today was I needed to write a unit test for a controller action which under certain condition redirects to a different action using the redirect helper:

  1. $this->redirect->roToute('routeName', array('controller' => 'index', 'action' = 'index'));

Unit testing a controller action was not a problem, I figured that out a week or two ago. In order to write an assertion for redirection, you will need to create a new instance of Zend\Mvc\Router\SimpleRouteStack and add routes you are testing for to it. Then attach the router to Zend\Mvc\MvcEvent.

So include few classes from Zend library plus the controller you want to test:

  1. use MyModule\Controller\IndexController,
  2.     Zend\Http\Request,
  3.     Zend\Http\Response,
  4.     Zend\Mvc\MvcEvent,
  5.     Zend\Mvc\Router\RouteMatch,
  6.     Zend\Mvc\Router\SimpleRouteStack,
  7.     Zend\Mvc\Router\Http\Segment,

Then put this inside your PHPUnit test case’s setUp method:

  1. public function setUp()
  2. {
  3.     $this->_controller = new IndexController;
  4.     $this->_request = new Request;
  5.     $this->_response = new Response;
  6.  
  7.     $this->_event = new MvcEvent();
  8.  
  9.     $routeStack = new SimpleRouteStack;
  10.     $route = new Segment('/mymodule/[:controller/[:action/]]');
  11.     $routeStack->addRoute('mymodule', $route);
  12.     $this->_event->setRouter($routeStack);
  13.  
  14.     $routeMatch = new RouteMatch(array('controller' => 'index', 'action' => 'index'));
  15.     $routeMatch->setMatchedRouteName('admin');
  16.     $this->_event->setRouteMatch($routeMatch);
  17.  
  18.     $this->_controller->setEvent($this->_event);
  19. }

After you have done all that, there are two ways how to assert a redirection has actually happened.

First, you can test for a 302 HTTP status:

  1. public function testIndexActionRedirectsByHttpStatus()
  2. {
  3.     $this->_controller->dispatch($this->_request, $this->_response);
  4.     $this->assertEquals(302, $this->_response->getStatusCode());
  5. }

Second, you can check for the Location header:

  1. public function testIndexActionRedirectsToCorrectUri()
  2. {
  3.     $this->_controller->dispatch($this->_request, $this->_response);
  4.     $this->assertEquals('/mymodule/mycontroller/myaction/', $this->_event->getResponse()->getHeaders()->get('Location')->getUri());
  5. }

Ideally use both assertions to be sure.

Create a self signed X509 certificate in Python

2012 August 5

Here is how to create a self signed certificate in Python using OpenSSL:

  1. from OpenSSL import crypto, SSL
  2. from socket import gethostname
  3. from pprint import pprint
  4. from time import gmtime, mktime
  5.  
  6. CERT_FILE = "selfsigned.crt"
  7. KEY_FILE = "private.key"
  8.  
  9. def create_self_signed_cert():
  10.             
  11.         # create a key pair
  12.         k = crypto.PKey()
  13.         k.generate_key(crypto.TYPE_<wbr>RSA, 1024)
  14.  
  15.         # create a self-signed cert
  16.         cert = crypto.X509()
  17.         cert.get_subject().C = "UK"
  18.         cert.get_subject().ST = "London"
  19.         cert.get_subject().L = "London"
  20.         cert.get_subject().O = "Dummy Company Ltd"
  21.         cert.get_subject().OU = "Dummy Company Ltd"
  22.         cert.get_subject().CN = gethostname()
  23.         cert.set_serial_number(1000)
  24.         cert.gmtime_adj_notBefore(0)
  25.         cert.gmtime_adj_notAfter(10*<wbr>365*24*60*60)
  26.         cert.set_issuer(cert.get_<wbr>subject())
  27.         cert.set_pubkey(k)
  28.         cert.sign(k, 'sha1')
  29.  
  30.         open(CERT_FILE, "wt").write(
  31.             crypto.dump_certificate(<wbr>crypto.FILETYPE_PEM, cert))
  32.         open(KEY_FILE, "wt").write(
  33.             crypto.dump_privatekey(crypto.<wbr>FILETYPE_PEM, k))
  34.  
  35. create_self_signed_cert()

You can then use m2crypto library to encrypt and decrypt data using this self signed certificate. You use public key to encrypt and private key to decrypt:

  1. f = open(CERT_FILE)
  2. cert_buffer = f.read()
  3. f.close()
  4.  
  5. from M2Crypto import RSA, X509 
  6. cert = X509.load_cert_string(cert_<wbr>buffer, X509.FORMAT_PEM) 
  7. pub_key = cert.get_pubkey() 
  8. rsa_key = pub_key.get_rsa() 
  9. cipher = rsa_key.public_encrypt('<wbr>plaintext', RSA.pkcs1_padding)
  10.  
  11. print cipher
  12.  
  13. ReadRSA = RSA.load_key(KEY_FILE)
  14. try:
  15.     plaintext = ReadRSA.private_decrypt (cipher, RSA.pkcs1_padding)
  16. except:
  17.     print "Error: wrong key?"
  18.     plaintext = ""
  19.  
  20. print plaintext

Merge sort PHP implementation

2012 June 27
by Richard Knop

After a short pause I am continuing my challenge to implement all sorting algorithms listed on Wikipedia in PHP. Merge sort is a bit more advanced than previous algorithms but once you figure it out it’s quite neat.

Personally, I hate recursion and try to avoid it as much as possible (speaking of recursion, check out my weblogs about Adjacency list model and Nested set model – which is in my opinion a better solution in most cases) – but sorting is one area where recursion is needed.

Merge sort was invented by John Von Neumann, a big name in computer science history. It is a divide and conquer algorithm. It sorts arrays by dividing them recursively into halves (divide) and then sorting and merging them back together (conquer).

The good thing about this algorithm is it preserves order of equal elements (if you have two 25s in an array, merge sort will place the one that came earlier in the original array on the left side).

Here is my PHP implementation consisting of two functions: divide and conquer:

  1. <?php
  2.  
  3. $arr = array();
  4. for ($i = 0; $i < 100; ++$i) {
  5.     $arr[] = $i;
  6. }
  7. shuffle($arr);
  8. $sortedArr = divide($arr);
  9. var_dump($sortedArr);
  10.  
  11. function divide(array $arr) {
  12.     if (1 === count($arr)) {
  13.         return $arr;
  14.     }
  15.     $left = $right = array();
  16.     $middle = round(count($arr)/2);
  17.     for ($i = 0; $i < $middle; ++$i) {
  18.         $left[] = $arr[$i];
  19.     }
  20.     for ($i = $middle; $i < count($arr); ++$i) {
  21.         $right[] = $arr[$i];
  22.     }
  23.     $left = divide($left);
  24.     $right = divide($right);
  25.     return conquer($left, $right);
  26. }
  27.  
  28. function conquer(array $left, array $right) {
  29.     $result = array();
  30.     while (count($left) > 0 || count($right) > 0) {
  31.         if (count($left) > 0 && count($right) > 0) {
  32.             $firstLeft = current($left);
  33.             $firstRight = current($right);
  34.             if ($firstLeft <= $firstRight) {
  35.                 $result[] = array_shift($left);
  36.             } else {
  37.                 $result[] = array_shift($right);
  38.             }
  39.         } else if (count($left) > 0) {
  40.             $result[] = array_shift($left);
  41.         } else if (count($right) > 0) {
  42.             $result[] = array_shift($right);
  43.         }
  44.     }
  45.     return $result;
  46. }

Which will output:

array(100) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
  [8]=>
  int(8)
  [9]=>
  int(9)
  [10]=>
  int(10)
  [11]=>
  int(11)
  [12]=>
  int(12)
  [13]=>
  int(13)
  [14]=>
  int(14)
  [15]=>
  int(15)
  [16]=>
  int(16)
  [17]=>
  int(17)
  [18]=>
  int(18)
  [19]=>
  int(19)
  [20]=>
  int(20)
  [21]=>
  int(21)
  [22]=>
  int(22)
  [23]=>
  int(23)
  [24]=>
  int(24)
  [25]=>
  int(25)
  [26]=>
  int(26)
  [27]=>
  int(27)
  [28]=>
  int(28)
  [29]=>
  int(29)
  [30]=>
  int(30)
  [31]=>
  int(31)
  [32]=>
  int(32)
  [33]=>
  int(33)
  [34]=>
  int(34)
  [35]=>
  int(35)
  [36]=>
  int(36)
  [37]=>
  int(37)
  [38]=>
  int(38)
  [39]=>
  int(39)
  [40]=>
  int(40)
  [41]=>
  int(41)
  [42]=>
  int(42)
  [43]=>
  int(43)
  [44]=>
  int(44)
  [45]=>
  int(45)
  [46]=>
  int(46)
  [47]=>
  int(47)
  [48]=>
  int(48)
  [49]=>
  int(49)
  [50]=>
  int(50)
  [51]=>
  int(51)
  [52]=>
  int(52)
  [53]=>
  int(53)
  [54]=>
  int(54)
  [55]=>
  int(55)
  [56]=>
  int(56)
  [57]=>
  int(57)
  [58]=>
  int(58)
  [59]=>
  int(59)
  [60]=>
  int(60)
  [61]=>
  int(61)
  [62]=>
  int(62)
  [63]=>
  int(63)
  [64]=>
  int(64)
  [65]=>
  int(65)
  [66]=>
  int(66)
  [67]=>
  int(67)
  [68]=>
  int(68)
  [69]=>
  int(69)
  [70]=>
  int(70)
  [71]=>
  int(71)
  [72]=>
  int(72)
  [73]=>
  int(73)
  [74]=>
  int(74)
  [75]=>
  int(75)
  [76]=>
  int(76)
  [77]=>
  int(77)
  [78]=>
  int(78)
  [79]=>
  int(79)
  [80]=>
  int(80)
  [81]=>
  int(81)
  [82]=>
  int(82)
  [83]=>
  int(83)
  [84]=>
  int(84)
  [85]=>
  int(85)
  [86]=>
  int(86)
  [87]=>
  int(87)
  [88]=>
  int(88)
  [89]=>
  int(89)
  [90]=>
  int(90)
  [91]=>
  int(91)
  [92]=>
  int(92)
  [93]=>
  int(93)
  [94]=>
  int(94)
  [95]=>
  int(95)
  [96]=>
  int(96)
  [97]=>
  int(97)
  [98]=>
  int(98)
  [99]=>
  int(99)
}

Best way to understand how it works is to apply it to a smaller array and add a little debugging inside the functions so we can see what’s happening. After a little tweaking:

  1. <?php
  2.  
  3. $arr = array(4, 5, 1, 3, 2);
  4. $sortedArr = divide($arr);
  5. var_dump($sortedArr);
  6.  
  7. function divide(array $arr) {
  8.     if (1 === count($arr)) {
  9.         return $arr;
  10.     }
  11.     $left = $right = array();
  12.     $middle = round(count($arr)/2);
  13.     for ($i = 0; $i < $middle; ++$i) {
  14.         $left[] = $arr[$i];
  15.     }
  16.     for ($i = $middle; $i < count($arr); ++$i) {
  17.         $right[] = $arr[$i];
  18.     }
  19.     $left = divide($left);
  20.     $right = divide($right);
  21.     echo "We are going to conquer these two arrays:\narray(",
  22.     implode(", ", $left), ")\narray(", implode(", ", $right), ")\n";
  23.     $conquered = conquer($left, $right);
  24.     echo "After conquering we get: array(", implode(", ", $conquered), ")\n\n";
  25.     return $conquered;
  26. }
  27.  
  28. function conquer(array $left, array $right) {
  29.     $result = array();
  30.     while (count($left) > 0 || count($right) > 0) {
  31.         if (count($left) > 0 && count($right) > 0) {
  32.             $firstLeft = current($left);
  33.             $firstRight = current($right);
  34.             if ($firstLeft <= $firstRight) {
  35.                 $result[] = array_shift($left);
  36.             } else {
  37.                 $result[] = array_shift($right);
  38.             }
  39.         } else if (count($left) > 0) {
  40.             $result[] = array_shift($left);
  41.         } else if (count($right) > 0) {
  42.             $result[] = array_shift($right);
  43.         }
  44.     }
  45.     return $result;
  46. }

Which will output a nice explanation of what’s happening, we can see what steps are being done and in what order:

We are going to conquer these two arrays:
array(4)
array(5)
After conquering we get: array(4, 5)

We are going to conquer these two arrays:
array(4, 5)
array(1)
After conquering we get: array(1, 4, 5)

We are going to conquer these two arrays:
array(3)
array(2)
After conquering we get: array(2, 3)

We are going to conquer these two arrays:
array(1, 4, 5)
array(2, 3)
After conquering we get: array(1, 2, 3, 4, 5)

array(5) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
}

By the way, here are my previous posts from this challenge:

  1. Bubble sort algorithm PHP implementation
  2. Selection sort algorithm PHP implementation
  3. Insertion sort algorithm PHP implementation
  4. Shellsort PHP implementation
  5. Comb sort PHP implementation

Comb sort PHP implementation

2012 June 19
tags:
by Richard Knop

After tackling the Shellsort, Comb sort is very similar. Shellsort was basically a generalisation of the Insertion sort, Comb sort is a generalisation of the Bubble sort. In the same way Shellsort was decreasing a gap between elements for subarrays been sent as input to the Insertion sort function, Comb sort is also decreasing the gap after every iteration and sending increasingly lengthy subarrays to the Bubble sort function.

According to Wikipedia, this algorithm works best with a shrink factor of around 1.3 (a little less than that but let’s keep this simple).

Here is my implementation:

  1. <?php
  2.  
  3. define('SHRINK_FACTOR', 1.3);
  4.  
  5. $arr = array();
  6. for ($i = 0; $i < 100; ++$i) {
  7.     $arr[] = $i;
  8. }
  9. shuffle($arr);
  10. $sortedArr = combSort($arr);
  11. var_dump($sortedArr);
  12.  
  13. function combSort(array $arr) {
  14.     $gap = floor(count($arr)/SHRINK_FACTOR);
  15.     while ($gap > 0) {
  16.         for ($i = 0; $i < count($arr)-$gap; ++$i) {
  17.             $arrWithGapsKeys = array();
  18.             $arrWithGaps = array();
  19.             $loop = true;
  20.             $j = $i;
  21.             while ($loop) {
  22.                 if (isset($arr[$j])) {
  23.                     $arrWithGapsKeys[] = (int)$j;
  24.                     $arrWithGaps[] = $arr[$j];
  25.                     $j += $gap;
  26.                 } else {
  27.                     $loop = false;
  28.                 }
  29.             }
  30.             $arrWithGapsOrdered = bubbleSort($arrWithGaps);
  31.             foreach ($arrWithGapsKeys as $key) {
  32.                 $arr[$key] = current($arrWithGapsOrdered);
  33.                 next($arrWithGapsOrdered);
  34.             }
  35.         }
  36.         $gap = floor($gap/SHRINK_FACTOR);
  37.     }
  38.     return $arr;
  39. }
  40.  
  41. function bubbleSort(array $arr) {
  42.     $sorted = false;
  43.     while (false === $sorted) {
  44.         $sorted = true;
  45.         for ($i = 0; $i < count($arr)-1; ++$i) {
  46.             $current = $arr[$i];
  47.             $next = $arr[$i+1];
  48.             if ($next < $current) {
  49.                 $arr[$i] = $next;
  50.                 $arr[$i+1] = $current;
  51.                 $sorted = false;
  52.             }
  53.         }
  54.     }
  55.     return $arr;
  56. }

Which will result in:

array(100) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
  [8]=>
  int(8)
  [9]=>
  int(9)
  [10]=>
  int(10)
  [11]=>
  int(11)
  [12]=>
  int(12)
  [13]=>
  int(13)
  [14]=>
  int(14)
  [15]=>
  int(15)
  [16]=>
  int(16)
  [17]=>
  int(17)
  [18]=>
  int(18)
  [19]=>
  int(19)
  [20]=>
  int(20)
  [21]=>
  int(21)
  [22]=>
  int(22)
  [23]=>
  int(23)
  [24]=>
  int(24)
  [25]=>
  int(25)
  [26]=>
  int(26)
  [27]=>
  int(27)
  [28]=>
  int(28)
  [29]=>
  int(29)
  [30]=>
  int(30)
  [31]=>
  int(31)
  [32]=>
  int(32)
  [33]=>
  int(33)
  [34]=>
  int(34)
  [35]=>
  int(35)
  [36]=>
  int(36)
  [37]=>
  int(37)
  [38]=>
  int(38)
  [39]=>
  int(39)
  [40]=>
  int(40)
  [41]=>
  int(41)
  [42]=>
  int(42)
  [43]=>
  int(43)
  [44]=>
  int(44)
  [45]=>
  int(45)
  [46]=>
  int(46)
  [47]=>
  int(47)
  [48]=>
  int(48)
  [49]=>
  int(49)
  [50]=>
  int(50)
  [51]=>
  int(51)
  [52]=>
  int(52)
  [53]=>
  int(53)
  [54]=>
  int(54)
  [55]=>
  int(55)
  [56]=>
  int(56)
  [57]=>
  int(57)
  [58]=>
  int(58)
  [59]=>
  int(59)
  [60]=>
  int(60)
  [61]=>
  int(61)
  [62]=>
  int(62)
  [63]=>
  int(63)
  [64]=>
  int(64)
  [65]=>
  int(65)
  [66]=>
  int(66)
  [67]=>
  int(67)
  [68]=>
  int(68)
  [69]=>
  int(69)
  [70]=>
  int(70)
  [71]=>
  int(71)
  [72]=>
  int(72)
  [73]=>
  int(73)
  [74]=>
  int(74)
  [75]=>
  int(75)
  [76]=>
  int(76)
  [77]=>
  int(77)
  [78]=>
  int(78)
  [79]=>
  int(79)
  [80]=>
  int(80)
  [81]=>
  int(81)
  [82]=>
  int(82)
  [83]=>
  int(83)
  [84]=>
  int(84)
  [85]=>
  int(85)
  [86]=>
  int(86)
  [87]=>
  int(87)
  [88]=>
  int(88)
  [89]=>
  int(89)
  [90]=>
  int(90)
  [91]=>
  int(91)
  [92]=>
  int(92)
  [93]=>
  int(93)
  [94]=>
  int(94)
  [95]=>
  int(95)
  [96]=>
  int(96)
  [97]=>
  int(97)
  [98]=>
  int(98)
  [99]=>
  int(99)
}

There are some variations of the Comb sort algorithm Combsort11 or Combsort with different end. I will show you how to implement them in the future.

Shellsort PHP implementation

2012 June 19
tags:
by Richard Knop

Continuing my challenge, after implementing Bubble sort, Selection sort and Insertion sort, here comes Shellsort. Named after Donald Shell, it is basically a generalisation of simpler algorithms like Bubble sort or Insertion sort. It starts with far apart elements. The gap between elements is then decreased after every iteration.

That means we start with small subarrays and then with every iteration the subarrays are getting bigger as we are decreasing the gap between elements. I chose to start with a gap equal to half of the array length rounded down. After every iteration I divide the gap by two and round down again until zero is reached.

Example:

  1. <?php
  2.  
  3. $arr = array();
  4. for ($i = 0; $i < 100; ++$i) {
  5.     $arr[] = $i;
  6. }
  7. shuffle($arr);
  8. $sortedArr = shellSort($arr);
  9. var_dump($sortedArr);
  10.  
  11. function shellSort(array $arr) {
  12.     $gap = floor(count($arr)/2);
  13.     while ($gap > 0) {
  14.         for ($i = 0; $i < count($arr)-$gap; ++$i) {
  15.             $arrWithGapsKeys = array();
  16.             $arrWithGaps = array();
  17.             $loop = true;
  18.             $j = $i;
  19.             while ($loop) {
  20.                 if (isset($arr[$j])) {
  21.                     $arrWithGapsKeys[] = (int)$j;
  22.                     $arrWithGaps[] = $arr[$j];
  23.                     $j += $gap;
  24.                 } else {
  25.                     $loop = false;
  26.                 }
  27.             }
  28.             $arrWithGapsOrdered = insertionSort($arrWithGaps);
  29.             foreach ($arrWithGapsKeys as $key) {
  30.                 $arr[$key] = current($arrWithGapsOrdered);
  31.                 next($arrWithGapsOrdered);
  32.             }
  33.         }
  34.         $gap = floor($gap/2);
  35.     }
  36.     return $arr;
  37. }
  38.  
  39. function insertionSort(array $table) {
  40.     $leftHand = array();
  41.     foreach ($table as $card) {
  42.         if (0 === count($leftHand)) {
  43.             $leftHand[] = $card;
  44.         } else {
  45.             $insertedCard = false;
  46.             $reindexedLeftHand = array();
  47.             for ($i = count($leftHand)-1; $i >= 0; $i) {
  48.                 if ($card >= $leftHand[$i]) {
  49.                     for ($j = 0; $j <= $i; ++$j) {
  50.                         $reindexedLeftHand[$j] = $leftHand[$j];
  51.                     }
  52.                     $reindexedLeftHand[] = $card;
  53.                     for ($j = $i+1; $j < count($leftHand); ++$j) {
  54.                         $reindexedLeftHand[$j+1] = $leftHand[$j];
  55.                     }
  56.                     $insertedCard = true;
  57.                     break;
  58.                 }
  59.             }
  60.             if (false === $insertedCard) {
  61.                 $reindexedLeftHand[] = $card;
  62.                 foreach ($leftHand as $cardInLeftHand) {
  63.                     $reindexedLeftHand[] = $cardInLeftHand;
  64.                 }
  65.             }
  66.             $leftHand = $reindexedLeftHand;
  67.         }
  68.     }
  69.     return $leftHand;
  70. }

Will result in:

array(100) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
  [8]=>
  int(8)
  [9]=>
  int(9)
  [10]=>
  int(10)
  [11]=>
  int(11)
  [12]=>
  int(12)
  [13]=>
  int(13)
  [14]=>
  int(14)
  [15]=>
  int(15)
  [16]=>
  int(16)
  [17]=>
  int(17)
  [18]=>
  int(18)
  [19]=>
  int(19)
  [20]=>
  int(20)
  [21]=>
  int(21)
  [22]=>
  int(22)
  [23]=>
  int(23)
  [24]=>
  int(24)
  [25]=>
  int(25)
  [26]=>
  int(26)
  [27]=>
  int(27)
  [28]=>
  int(28)
  [29]=>
  int(29)
  [30]=>
  int(30)
  [31]=>
  int(31)
  [32]=>
  int(32)
  [33]=>
  int(33)
  [34]=>
  int(34)
  [35]=>
  int(35)
  [36]=>
  int(36)
  [37]=>
  int(37)
  [38]=>
  int(38)
  [39]=>
  int(39)
  [40]=>
  int(40)
  [41]=>
  int(41)
  [42]=>
  int(42)
  [43]=>
  int(43)
  [44]=>
  int(44)
  [45]=>
  int(45)
  [46]=>
  int(46)
  [47]=>
  int(47)
  [48]=>
  int(48)
  [49]=>
  int(49)
  [50]=>
  int(50)
  [51]=>
  int(51)
  [52]=>
  int(52)
  [53]=>
  int(53)
  [54]=>
  int(54)
  [55]=>
  int(55)
  [56]=>
  int(56)
  [57]=>
  int(57)
  [58]=>
  int(58)
  [59]=>
  int(59)
  [60]=>
  int(60)
  [61]=>
  int(61)
  [62]=>
  int(62)
  [63]=>
  int(63)
  [64]=>
  int(64)
  [65]=>
  int(65)
  [66]=>
  int(66)
  [67]=>
  int(67)
  [68]=>
  int(68)
  [69]=>
  int(69)
  [70]=>
  int(70)
  [71]=>
  int(71)
  [72]=>
  int(72)
  [73]=>
  int(73)
  [74]=>
  int(74)
  [75]=>
  int(75)
  [76]=>
  int(76)
  [77]=>
  int(77)
  [78]=>
  int(78)
  [79]=>
  int(79)
  [80]=>
  int(80)
  [81]=>
  int(81)
  [82]=>
  int(82)
  [83]=>
  int(83)
  [84]=>
  int(84)
  [85]=>
  int(85)
  [86]=>
  int(86)
  [87]=>
  int(87)
  [88]=>
  int(88)
  [89]=>
  int(89)
  [90]=>
  int(90)
  [91]=>
  int(91)
  [92]=>
  int(92)
  [93]=>
  int(93)
  [94]=>
  int(94)
  [95]=>
  int(95)
  [96]=>
  int(96)
  [97]=>
  int(97)
  [98]=>
  int(98)
  [99]=>
  int(99)
}

Insertion sort algorithm PHP implementation

2012 June 19
by Richard Knop

This is a third blog post in my challenge to cover as many sorting algorithms as possible, implement them in PHP (without using any array functions) and then benchmark their performance with different inputs. Could be interesting.

Insertion sort is another common sorting algorithm. To explain how it works, try to imagine this. There’s a couple of cards on the table and you want to sort them in a correct order. You will pick a card from the table (based on any criteria, it doesn’t really matter, you can just pick the cards up randomly) and put it in your left hand at a correct position. To determine the correct position, you will compare it with every other card in your left hand starting from the right. This is a similar algorithm you might unconsciously use when playing cards with your friends.

Example:

  1. <?php
  2.  
  3. $table = array(7, 3, 9, 6, 5, 1, 2, 0, 8, 4);
  4. $leftHand = insertionSort($table);
  5. var_dump($leftHand);
  6.  
  7. function insertionSort(array $table) {
  8.     $leftHand = array();
  9.     foreach ($table as $card) {
  10.         if (0 === count($leftHand)) {
  11.             $leftHand[] = $card;
  12.         } else {
  13.             $insertedCard = false;
  14.             $reindexedLeftHand = array();
  15.             for ($i = count($leftHand)-1; $i >= 0; $i) {
  16.                 if ($card >= $leftHand[$i]) {
  17.                     for ($j = 0; $j <= $i; ++$j) {
  18.                         $reindexedLeftHand[$j] = $leftHand[$j];
  19.                     }
  20.                     $reindexedLeftHand[] = $card;
  21.                     for ($j = $i+1; $j < count($leftHand); ++$j) {
  22.                         $reindexedLeftHand[$j+1] = $leftHand[$j];
  23.                     }
  24.                     $insertedCard = true;
  25.                     break;
  26.                 }
  27.             }
  28.             if (false === $insertedCard) {
  29.                 $reindexedLeftHand[] = $card;
  30.                 foreach ($leftHand as $cardInLeftHand) {
  31.                     $reindexedLeftHand[] = $cardInLeftHand;
  32.                 }
  33.             }
  34.             $leftHand = $reindexedLeftHand;
  35.         }
  36.     }
  37.     return $leftHand;
  38. }

Will result in:

array(10) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
  [8]=>
  int(8)
  [9]=>
  int(9)
}