2012-07-31

What Iterators Can Do For You

Basically Iterators provide a list interface for an object. Like all interfaces they are a contract how something can be used. If you use an interface it is not relevant how it is implemented - the implementation logic is encapsulated.

It is of course relevant on the integration level. A bad implementation can impact the performance of you application. Even an good implementation may need special resources (like a database). But all this does not impact how you use it. Your code using the object with the Iterator interface stays the same.

Let's start with a simple example that outputs a list.

$elements = array(
  'line one', 'line two'
);

foreach ($lines as $key => $value) {
  echo $key.': '.$value."\n";
}


If we transfer this into an object it would like that:

class MyProjectLineOutput {
  private $_lines = NULL;

  public function __construct($lines) {
    $this->_lines = $lines;
  }

  public function __invoke() {
    foreach ($this->_lines as $key => $value) {
      echo $key.': '.$value."\n";
    }
  }
}

$output = new MyProjectLineOutput(
  array(
    'line one', 'line two'
  )
);
$output();


On the first glance that looks like a lot more work but it isn't. The code includes two tasks. Get the lines and output them. The class encapsulates the output task and makes it reusable. In this simple example that may look superfluous but think a little larger. Like output an select-field or csv.

Encapsulate file()


Still we haven't used an Iterator, but just encapsulated the output. PHP provides several default iterators and one of them is the ArrayIterator.

$output = new MyProjectLineOutput(
  new ArrayIterator(
    array(
      'line one', 'line two'
    )
  )
);
$output();


The ArrayIterator just takes an array and makes it an Iterator. It is mostly used to implement another interface - IteratorAggregate. Both the "Iterator" and the "IteratorAggregate" interfaces inherit from a common ancestor named "Traversable". You can not implement "Traversable" directly but use it to validate if an object is traversable or in other words can be used with foreach.

Now let's load the lines from a file.

class MyProjectFile implements IteratorAggregate {
  private $_file;

  public function __construct($file) {
    $this->_file = $file;
  }

  public function getIterator() {
    return new ArrayIterator(file($this->_file));
  }
}

$output = new MyProjectLineOutput(
  new MyProjectFile('sample.txt')
);
$output();


The main difference between using file directly to this is that the file() is accessed later in the process. The foreach() inside the MyProjectLineOutput::output() method calls MyProjectFile::getIterator(). Until then we can pass the instance of MyProjectFile around without loading the file into memory. Unlike a direct call to file() we don't pass the concrete data around but an information how it can be obtained.

Iterating A Text File


Implementing Iterator we can make sure that only a part of the file needs to be loaded.

class MyProjectFileUnbuffered implements Iterator {
  private $_file;
  private $_handle = NULL;
  private $_key = -1;
  private $_current = NULL;

  public function __construct($file) {
    $this->_file = $file;
  }

  public function __destruct() {
    if (is_resource($this->_handle)) {
      fclose($this->_handle);
    }
  }

  public function rewind() {
    if (!is_resource($this->_handle)) {
      $this->_handle = fopen($this->_file, 'r');
    } else {
      fseek($this->_handle, 0);
    }
    $this->_key = -1;
    $this->next();
  }

  public function next() {
    if ($this->_key > 0 or $this->_current !== FALSE) {
      $this->_current = fgets($this->_handle);
      $this->_key++;
    }
  }

  public function key() {
    return $this->_key;
  }

  public function current() {
    return $this->_current;
  }

  public function valid() {
    return $this->_current !== FALSE;
  }
}


This is more source then implementing it directly. Mostly because of the class and function declarations. But you have to write this only once. And it can be improved or replaced without affecting the usage.

Map Elements

Using iterators you can encapsulate mapping actions, like using array_map() on an array but only for elements that are read. Let's say you need to chop all trailing whitespaces from the lines.

Step One: Map Iterator:


class MyProjectMapIterator implements OuterIterator {

  private $_innerIterator = NULL;
  private $_callback = NULL;

  public function __construct(Iterator $innerIterator, $callback) {
    $this->_innerIterator = $innerIterator;
    $this->_callback = $callback;
  }

  public function map($current, $key) {
    return call_user_func($this->_callback, $current, $key);
  }

  public function getInnerIterator() {
    return $this->_innerIterator;
  }

  public function rewind() {
    $this->getInnerIterator()->rewind();
  }

  public function next() {
    $this->getInnerIterator()->next();
  }

  public function key() {
    return $this->getInnerIterator()->key();
  }

  public function current() {
    return $this->map(
      $this->getInnerIterator()->current(),
      $this->getInnerIterator()->key()
    );
  }

  public function valid() {
    return $this->getInnerIterator()->valid();
  }
}


OuterIterator is an interface for iterators that wraps other iterators, it is defined in the SPL. It extends the Iterator interface. The MapIterator is an iterator of that kind, so it is cleaner to implement it that way.

Step Two: Using The Map Iterator:

Using the map iterator is not unlike using array_map.

$output = new MyProjectLineOutput(
  new MyProjectMapIterator(
    new MyProjectFile('sample.txt'),
    function($current, $key) {
      return chop($current);
    }
  )
);
$output();


The file() function has an option to do this. But it is limited to exactly this task. With MapIterator you get a lot more flexibility. You could even extend the MapIterator to get reusable mappings.

Step Three: Extending the Map Iterator

class MyProjectMapIteratorUpper extends MyProjectMapIterator {

  public function __construct(Iterator $innerIterator) {
    parent::__construct(
      $innerIterator,
      function($current, $key) {
        return strToUpper($current);
      }
    );
  }
}

Filter Elements:

Here is another option for file(), that skips empty lines. This would be filter task and here is already an superclass for that in SPL.

class MyProjectFilterIteratorSkipEmptyLines extends FilterIterator {

  public function accept() {
    return trim($this->getInnerIterator()->current()) !== '';
  }
}

Conclusion

Iterators are not about writing less code at one time. But they help you to write source that is encapsulated, easy to test and reusable. Because of this over time you will end up with less code.

2012-07-30

Using The PHP 5.4 Webserver On Windows

Starting a server from the command line
PHP 5.4 has an built-in webserver. For local development it is not necessary to install Apache Httpd or another webserver anymore. You can just start an server from the command line.

Change the directory to your project directory. The argument -S starts the webserver. You need to specify a host and a port. All requests are shown in the console window.

A Shortcut

To make things a little easier you can create a windows shortcut. This allows you to change the console window size, font and color, too. The following pictures show the particular steps:
Step 1: Create A Shortcut
Step 2: Select the PHP binary
Step 3: Name the shortcut
Step 4: Change command and working directory
Step 5: Change the window size

2012-07-14

Matching Classes In XSLT

A while ago (well 2 years) I posted an entry about the differences between CSS selectors and Xpath expressions. An simple ".classname" in CSS is a noisy "contains(concat(' ', normalize-space(@class), ' '), ' first ')" in Xpath.

In XSLT this adds a lot of overhead. But if your XSLT processor supports EXSLT you are able to encapsulate it into a function.

I put this into a file "contains-token.xsl".


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:func="http://exslt.org/functions"
  extension-element-prefixes="func"
>
<func:function name="func:contains-token">
  <xsl:param name="haystack">
  <xsl:param name="needle">
  <xsl:variable name="normalizedHaystack" select="concat(' ', normalize-space($haystack), ' ')"/>
  <xsl:variable name="normalizedNeedle" select="concat(' ', normalize-space($needle), ' ')"/>
  <func:result select="$needle != '' and contains($haystack, $needle)"/>
</func:function>

</xsl:stylesheet>


You need to declare the func namespace and define it as an extension prefix. The function definition is not unlike an normal template definition. You just have to use the "func:function" and "func:result" elements. Function always need to be inside an namespace. If in doubt, just use the "func" namespace itself.

In this case I normalize both parameters first and just validate if the haystack contains the needle.

Now it is possible to import the function and use it.


...
<xsl:import href="../functions/contains-token.xsl"/>

<xsl:template match="/">
  ...
  <xsl:value-of select=".//div[func:contains-token(@class, 'classname')]"/>
  ...
</xsl:template>
...


It is still longer then the CSS version but it is a lot more readable.


2012-04-19

Twin Stem Adapters

I don't like the standard Brompton handlebar. They are to short and to flexible. They are so short that I had to cut of a considerable amount of the right grip to fit the brake lever and the shifter. Not an ideal situation. The S Type is to low for me. One of the users in the German Bromptonauten forum posted an image of his modification. An M Type stem with a stem adapter raising a standard flat handlebar.

So I replaced the M Type stem on my Brompton with an H Type. It is 6cm higher, but the hinge is higher, too. I tested three stem adapters.



TranzX double clamp adapter SATORI Aberhallo Adjustable Stem GUB G-80 folding bike stem
Images
Distance 50 mm 50 mm 55 mm
Weight 188g 198g 141g
Colors black black red, silver, blue, black, gold
Remove Grip and break lever for assembly No No Yes


H Type stem, GUB G-80 adapter and flat handle bar
The major disadvantage of the TranzX adapter are the clamps above the handle bar. The GUB adapter is similiar but the clamps are at the bottom and smaller. The Aberhallo adapter has a different design - it is the most flexible. TranxZ and Aberhallo use plastic barends, but the GUB has threaded aluminium barends, providing a small storage space.

For now I am using the GUB G-80. The 5mm more make a difference (no conflict with the mudguard stay) and I like the look of the bands at the handle bar.

The handle bar is 1 meter from the ground and 8 cm lower then the saddle.

2012-04-14

Einladung zum Kölner Radverkehrstreff

Fast hätte ich es gar nicht mitbekommen, diesmal lädt die Polizei zum Kölner Radverkehrstreff ein. Die Pressemitteilung ist vom Donnerstag den 12.04.2012 - die Veranstaltung wird am Montag, den 16.04.2012 um 18:00 Uhr im Polizeipräsidium Köln (Walter-Pauli-Ring 2-6, Forum 1+2) stattfinden. Großzügige VIER Tage Zeit gibt man also den "interessierten Bürgerinnen und Bürgern" den Termin einzuplanen.

Die Stadt hat es bis heute (Samstag, 14.04.2012 16:00 Uhr)  nicht geschafft eine entsprechende Meldung auf ihrer Radverkehrsseite zu veröffentlichen und um Veranstaltungskalender ist sie auch nicht zu finden. Beim letzten Mal wurde die Ankündigung als Schlussabsatz in einer anderen Meldung untergebracht.

Das Thema ist passender weise diesmal "Fahrradkommunikation und Öffentlichkeitsarbeit".

2012-03-23

Brompton Modifications

I don't like the plastic silver look of the Brompton fenders. So I got some carbon fibre effect foil and a hairdryer. The result are some nice black fenders.


You can see my new rear suspension on the image, too. Here is a real steel spring inside. So it is nothing for weight weenies. :-)



2012-03-13

Brompton Mini O-Bag


It is an Ortlieb Ultimate Classic with two differences. First of course the Klickfix mounting adapter is replaced by a Brompton version.
The other difference is that it has a handle on to top and no push buttons for map cases. This makes sense because on a Brompton the bag is to low.


Update: Yes, the camera insert fits.

2012-02-02

My New Brompton

Yeah I got one. It is a modified Brompton from Junik-HPV. It has a Shimano Alfine 11, which makes it really nice to ride.


It is quite different from my Strida. The riding position is not as upright as on the Strida, but still comfortable and I finally have room for my knees. The folding is more complex and the resulting package is smaller but wider. The Strida is easier to transport while folded.

The folding of the Brompton is done in five steps plus one optional step for the pedal. The folding of the Strida needs only a single step with four optional steps for the both handle bars and pedals.

Brompton folding steps:
  1.  Move the right pedal in position
  2. Fold the rear
  3. Unscrew and fold the front
  4. Push the saddle into the frame
  5. Unscrew and fold the stem
  6. Optional: fold the left pedal
Strida folding steps:
  1. Fold the bottom tube up and the wheels against each other
  2. Optional: Left handle bar
  3. Optional: Right handle bar
  4. Optional: Left pedal
  5. Optional: Right pedal
The luggage options on a Brompton are a lot better then on the Strida. The front block is extremly useful and allows to transport a lot of stuff. It is connected to the frame, not the stem, so it does not affect the steering. You can add something comparable to the Strida using a Klick Fix Caddy. But on the Strida this makes the steering more difficult depending on the load.

Unlike the Strida the Brompton has a dynamo hub. So now I have light without thinking about batteries. I am thinking about an adapter so I can use it to charge devices during tours.





x