James Ball

Web Developer

Memoization With PHP

This article was updated at 2019-12-17 to add support for anonymous functions.

Are you making too many repeated calls to the same resource intensive functions? Do you need to optimise recursive function calls? Then memoization could help with that.

Definition

Memoization is a technique used to increase the speed of recursive or expensive functions by caching the results. When the same arguments occur again it will return the cache value otherwise it will run the function call.

Creating the Function

First We’ll start by creating a function that returns an anonymous function.

1
2
3
4
5
6
function memoize($function)
{
    return function () use ($function) {
        // 
    };
}

Then create an array that is stored statically to store the caches with static $caches = [].

1
2
3
4
5
6
7
8
function memoize($function)
{
    return function () use ($function) {
        static $caches = [];

        //
    };
}

Now we can store the arguments of the function with $arguments = func_get_args() and serialize the data to be used as a key $key = serialize($arguments).

1
2
3
4
5
6
7
8
9
10
11
function memoize($function)
{
    return function () use ($function) {
        static $caches = [];

        $arguments = func_get_args();
        $key = serialize($arguments);

        // 
    };
}

And then we’ll check if the entry exists ! array_key_exists($key, $caches) and if not compute then store the value with $caches[$key] = $function(...$arguments).

Finally we can return it via $caches[$key].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function memoize($function)
{
    return function () use ($function) {
        static $caches = [];

        $arguments = func_get_args();
        $key = serialize($arguments);

        if (! array_key_exists($key, $caches)) {
            $caches[$key] = $function(...$arguments);
        }

        return $caches[$key];
    };
}

Demonstration

Here we can create a function that’ll we’ll pass as an argument to memoize. In this example we’ll create a function that double the value passed; for a more real-world example this could be a function call within a recusive loop or a request to an API which would get recalled, like getting user, order, transaction, etc information.

In this cliche example we’ll cache the results of a fibonacci sequence with $memoizedFibonacci(10) and once which will calculate the value. On subsequent calls of $memoizedFibonacci(10) it will return the cached value in the example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$fibonacci = function ($number) {
    if ($number == 0) {
        return 0;
    } elseif ($number == 1) {
        return 1;
    } else {
        return fibonacci($number - 1) + fibonacci($number - 2);
    }
}

$memoizedFibonacci = memoize($add);

// 55
var_dump($memoizedFibonacci(10));

// 6765
var_dump($memoizedFibonacci(20));

// 55
// Since the exact same arguments have been used
// once already, this will return the cached result.
var_dump($memoizedDouble(10));

Or we make a call to an external API $memoizedUserFromApi('joe_bloggs') instead like so.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$getUserFromApi = function ($username) {
    return Http::get("http://someapi.net/users/{$username}");
};

$memoizedUserFromApi = memoize($getUserFromApi);

// JSON: { "username": "joe_bloggs", ... }
var_dump($memoizedUserFromApi('joe_bloggs'));

// JSON: { "username": "another_person", ... }
var_dump($memoizedUserFromApi('another_person'));

// JSON: { "username": "joe_bloggs", ... }
// Since the exact same arguments have been used
// once already, this will return the cached result.
var_dump($memoizedUserFromApi('joe_bloggs'));

In Conclusion

  • Memoization is a caching technique, which stores the result of a expensive function call.
  • It can be easily implemented to an existing code-base optimise it’s performance.
  • Memoization can also come in handy when working with 3rd party APIs which will return the same data if called again.

Reinstalling Existing Magento 1 Modules

Despite the fact that Magento has the <version> inside of it’s config files (with the exception of a newer mysql install file e.g. mysql4-install-1.1.0.php), it doesn’t check this and reload a new module when installed. If you need to reload the module and database setup then go to the database table core_resource.

1
2
3
4
5
6
7
+-------------------------+---------+
| code                    | version |
+-------------------------+---------+
| consignment_setup       | 1.0.0   | 
| etc ...                 |   ...   | 
+-------------------------+---------+
mysql>

Then clear Magento’s cache.

Always make sure to change the version of your install script before deploying. But while developing it is easier to drop the record from core_resource.

Linux CLI Cheatsheet

Here’s a cheat sheet of the core linux commands that I use daily.

Bash Commands

uname -a Show system and kernel
head -n1 /etc/issue Show distri­bution
mount Show mounted filesy­stems
date Show system date
uptime Show uptime
whoami Show your username
man command Show manual for command
watch -n 1 'date' Watch changes to the date each second then display output

 

Bash Variables

env Show enviro­nment variables
export NAME=value Set $NAME to value
$NAME Output value of $NAME variable
$PATH Executable search path
$HOME Home directory
$SHELL Current shell

 

Commmand Execution & IO

cmd, cmd1 and cmd2 refers to a command.

cmd1 ; cmd2 Run cmd1 then cmd2
cmd1 && cmd2 Run cmd2 if cmd1 is successful
cmd1 || cmd2 Run cmd2 if cmd1 is not successful
cmd & Run cmd in a subshell
cmd1 | cmd2 Pipe stdout of cmd1 to cmd2
cmd1 | cmd2 Pipe stderr of cmd1 to cmd2
cmd < file Input of cmd from file
cmd1 <(cmd2) Output of cmd2 as file input to cmd1
cmd > file Standard output stdout of cmd to file
cmd > /dev/null Discard stdout of cmd
cmd >> file Append stdout to file
cmd 2> file Error output stderr of cmd to file
cmd &> file Every output of cmd to file
cmd 1>&2 stdout to same place as stderr
cmd 2>&1 stderr to same place as stdout

 

Directories

pwd Show current directory
mkdir dir Make directory dir
cd dir Change directory to dir
cd .. Go up a directory
ls List files

 

Files

touch file1 Create file1
cat file1 file2 Concat­enate files and output
less file1 View and paginate file1
file file1 Get type of file1
cp file1 file2 Copy file1 to file2
mv file1 file2 Move file1 to file2
rm file1 Delete file1
head file1 Show first 10 lines of file1
tail file1 Show last 10 lines of file1
tail -F file1 Output last lines of file1 as it changes

 

File Permis­sions

chmod 775 file Change mode of file to 775
chmod -R 600 dir Recurs­ively chmod dir to 600
chown user:group file Change file owner to user and group to group

 

File Permission Bits

First digit is owner permis­sion, second is group and third is everyone. Calculate permission digits by adding numbers below.

4 read (r)
2 write (w)
1 execute (x)

 

ls Options

-a Show all (including hidden)
-R Recursive list
-r Reverse order
-t Sort by last modified
-S Sort by file size
-l Long listing format
-1 One file per line
-m Comma-­sep­arated output
-Q Quoted output

 

Search Files

grep pattern files Search for pattern in files
grep -i Case insens­itive search
grep -r Recursive search
grep -v Inverted search
grep -o Show matched part of file only
find /dir/ -name name* Find files starting with name in dir
find /dir/ -user name Find files owned by name in dir
find /dir/ -mmin num Find files modifed less than num minutes ago in dir
whereis command Find binary for command
locate file Find file (quick search of system index)

 

Processes

ps Show snapshot of processes
top Show real time processes
kill pid Kill process with id pid
pkill name Kill process with name name
killall name Kill all processes with names beginning name

 

Octopress: My Thoughts After Switching From Wordpress

Octopress is a framework built on top of Jekyll. It’s a static site generator which means that it lacks advance feature which would normally require scripting and a back-end like Wordpress. If you want to know whether you should switch to Octopress or would like to know some tweaks, tips or adjustments then continue through this post.

Why To Migrate From Wordpress

  • Wordpress is a great blogging and CMS platform, but it just had too many features for my personal blog.
  • So far I have found Octopress easier to maintain than Wordpress. There is no need to maintain wp-super-cache which serves up static pages in the same ways as Octopress along with not needing to manage a local and external LAMP stack.
  • WordPress blogs are a common target for hackers and spammers. To avoid this you need to keep your version of Wordpress constantly up to date.
  • Octopress allow you to create pages using Markdown instead of or along with HTML. Markdown has a cleaner, simpler and more readable syntax.
  • Octopress uses Jekyll to build pages. All pages of the pages are static and no server-side processing involved. This means that any requested page can deliver immediately by the server to the user.
  • Sharing code is really easy if your blogging about programming. It’s really useful to share code with Octopress, I normally write my posts in SublimeText 2 which is the editor I use to write most of my code in. I can copy and paste code snippets into my Octopress post and keep all the formatting and highlighting. As well as working in a more customizable environment than Wordpress.

Features You Might Miss

  • You can’t edit online from anywhere. With Wordpress a mobile app was available so you did not need to be at your computer/laptop to publish new posts.
  • Yay Markdown. Shame there is no solid way to manipulate images except by hand. I have currently worked around this by using Picasa to host my images which will cache my images and resize my images.
  • Octopress does not feature drafts, previews or publishing. When you deploy your site, you deploy everything. And the publication date is the date it was started, not when it’s finished.
  • Although it’s nice not having to use the web interface it’s also a feature which I also miss being able to post from anywhere, on almost any device.
  • By default Octopress can take a long time when compiling posts, there is a workaround for this by using page isolation.
  • Octopress has less plugins and themes available than Wordpress, If you want more features you will need to wait for someone to write it or write it yourself.
  • By default Octopress does not have a comment system. Although there is the option to use an external service for page comments such as Disqus. But using a service like this means that the comments are not hosted on your service and you lack the flexibility of the Wordpress commenting system.

So Why Did I Switch?

Octopress is a great platform targeted at programmers who want to start blogging without having the hassle of customizing static page generators and caching on Wordpress. Personally I think that Octopress is ideal for my personal blog or a blog maintained by several developers which is where version control becomes essential. Although it is not practical for other user like a normal blogger who just wants to write content, a copy-editor or a business looking for more advance features such as LOREMIPSUM.

Tips, Tweaks & Adjustments

I have written a list of features and improvements which can be made on top of Octopress as well as some useful tips to build pages quicker and setting up a 404 page.

Faster Page Generation Using Isolation

If you have a lot post in source/_posts then it could take a long time to compile your posts every time you update you blog.

If you are only working on 1 post at a time then it would make sense to only compile that page, to do this use rake isolate[post_name].
This will isolate the post your are working on then automatically move all other posts to source/_stash.

When you are ready to publish your site, use rake integrate, which will move all posts from source/_stash and move them back to source/_posts.

Custom 404 Page

This is taken from a tutorial I have written in the past.

Open up config.ru from the root directory and update the sinatra not_found route to the following:

config.ru
1
2
3
not_found do
  send_sinatra_file('404')
end

This will redirect to http://yourdomain.com/404/ where the page is found, but we still need to create a page.

To do this use rake new_page[404]. This will create a new file named index.markdown in your /source/404 directory:

404/indexlink
1
2
3
4
5
6
7
8
9
10
---
layout: page
title: "404 Error"
comments: false
sharing: false
footer: false
---
Whoops, the page you’re looking for cannot be found.

Maybe you can find what you are looking for in the [archives](/blog/archives/).

View my 404 page here.

Related Posts

There is a related post plugin already included in Jekyll, to use it open up the _layouts/posts.html template and edit it

1
<a>CODE...</a>

To enable this function open up _config.yml and set lsi: true
The lsi option will use a statistical analysis to calculate which pages are most relevant.
Now you need to install GSL using Ruby Gems.

1
gem install gsl

After GSL is installed you can regenerated your blog.

Category List / Cloud Tree

Download the files from Github.
1. Save tag_cloud.rb to plugins/tag_cloud.rb
2. Save category_list.html to source/_includes/custom/asides/category_list.html
3. Append to default_asides in _config.yml:

1
default_asides: [custom/asides/category_list.html]

This plugin was created by tokkonopapa.

Escaping Special Character In Markdown

You can escape special characters in Markdown used in formatting using a \. For a list of characters you can escape take a look at this article from Daring Fireball.

Popular Posts

  1. Open up your Gemfile and add this: gem 'octopress-popular-posts'
  2. Install it using Bundler: bundle install
  3. Run the installation command through Bundler: bundle exec octopress-popular-posts install
    The popular posts asides will now generate whenever you run: rake generate
  4. Open up config.yml and add this line:
1
popular_posts_count: 3

Append to default_asides in _config.yml:

1
default_asides: [custom/asides/popular_posts.html]

Offloading Images to Picasa

At first I hosted all of my images using Octopress, then later switch to Picasa to host my images becuase of the following.

  • Images will be delivered from CDN (free)
  • Images will cache & resize on the fly.
  • You can create custom image sizes.
  • Optimize image by selecting image quality.

Remove Blog Prefix

When Octopress is first set up by default all of your posts, categories and archives will be placed in the /blog/ directory. It is possible to remove this by doing the following:

  • Replace all /blog occurrences with a / in _config.yml
  • Move source/blog/archives to source/
  • Edit source/_includes/custom/navigation.html, replace /blog/archives with /archives
  • Edit source/index.html and replace /blog/archives with /archives

Even More Plugins?

If you are still looking for more reasons to switch, then browse the Jekyll and Octopress plugin archives.

CSS3: Animate Dog Eared Icons

TLDR: View the demo here

The HTML

The html for this is fairly simple. We are going to create a few divs and wrap them inside links.

1
2
3
4
5
<a href="#"><div class="file orange">&lt;&#47;&gt;</div></a>
<a href="#"><div class="file blue">js</div></a>
<a href="#"><div class="file red">rb</div></a>
<a href="#"><div class="file yellow">py</div></a>
<a href="#"><div class="file purple">&lt;?&gt;</div></a>

Creating The Icon

As we are using a link for the HTML we need the CSS to do all the work.

First start off by creating the style for the file classes. This will create a rectangular box with text in the center.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.file{
  background: #b0b0b0;
  border-radius: 5px;
  color: #fff;
  display: inline-block;
  font-family: Helvetica, Arial, sans-serif;
  font-size: 64px;
  font-weight: bold;
  height: 150px;
  margin: 10px;
  padding: 20px;
  line-height: 160px;
  text-align: center;
  width: 100px;
}

Creating The Dog Ear

Ok, nothing to fancy so far but we still need to create the dog ear for the top right of the icon. To do this we will be using borders to create a triangle which floats above the div using absolute and relative positioning.

One unusual thing about borders is that the browser draws them at an angle. One side of the border is colored for the colour of it’s sides (top, right, bottom, left), and the rest are left transparent. You can set the border width to a higher value e.g. 32px.

1
2
3
4
5
6
7
.border-effect{
  border-color:  red green blue orange;
  border-style: solid;
  border-width: 32px;
  width: 0;
  height: 0;
}

And it will output a shape like this.

Using this technique the left and bottom borders can be set to #888 & the top and right to #fff.

Here we have our shape now all we need to do is place it in the corner of our icon.

1
2
3
4
5
6
7
8
.dog-ear{
  border-color: #888 #fff;
  border-style: solid;
  border-width: 0 32px 32px 0;
  content: "";
  right: 0;
  top: 0;
}

If you want to learn more about border shapes take a look at this post by Jon Rohan.

Moving The Dog Ear

First lets rename our .dog-ear to .file:before. This will make the element appear directly before the and element with the class .file. Now we have our dog ear awkwardly sitting inside of our icon before our text; nobody wants that. To fix this we will make .file-before use the absolute positioning property. The element positioned relative to its first positioned parent element.

1
2
3
4
5
.file:before{
  position: absolute;
  right: 0;
  top: 0;
}

Well now there in the corner of the page, you can fix this by setting .file’s position to relative.

1
2
3
.file{
  position: relative;
}

Adding Some Colour

At the moment all of the elements look a bit drab; add some colour.

1
2
3
4
5
.orange{background:#ff7461;}.orange:before{border-color:#c65b4b #fff;}
.red{background:#ff6161;}.red:before{border-color:#c64b4b #fff;}
.yellow{background:#f4cf77;}.yellow:before{border-color:#cdad60 #fff;}
.blue{background:#8cc8ec;}.blue:before{border-color:#75a8c3 #fff;}
.purple{background:#b094de;font-size: 50px;}.purple:before{border-color:#8a75ad #fff;}

Animating The Icons

Now we have our icons finished, but they don’t do anything when you interact with them. We can use CSS3 transitions and transform to animate the shape when the user hover and clicks it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* This will reset the dog ear to make it look like it has unfolded. */
.file:hover:before{
  border-width: 0;
}

/* This zoom into the icon when you hover over it. */
.file:hover{
  transform: scale(1.05);
}

/* This zoom out the icon when you hover over it, then click. */
.file:hover:active{
  transform: scale(0.95);
}

Now for the finishing touch: transitions.

1
2
3
4
5
6
7
8
9
/* Don't forget to specify which properties you want to animate and avoid using "all" */

.file:before{
  transition: border 0.2s;
}

.file:hover{
  transition: transform 0.2s;
}

Now you animations will smoothly transition between one state to another.

The Final Product

View the demo of what we have just created.