Every class has an interface, every class can be typehinted as a method argument, typehint lets you specify the collaborator requirements. Not every typehint is the same… Example:
<?phpclassPaymentGateway{publicfunctioncharge($amount,BankAccount$account){// make a call to http web service here...$account->credit($amount)}}
The example above is fairly straightforward – we have a PaymentGateway class that requires a BankAccount collaborator for crediting amount to be charged in its charge function. Since we call credit() on the second argument – we typehint it to be of type BankAccount, which would prevent us from passing anything other than instances of that class. Let’s add some more requirements to our little example. Say we have checking and savings accounts, and we need to be able to charge both of them:
Since both accounts are subclasses of BankAccount – the typehint still works fine. However, we have now opened the possibility for abusing the typehint… In case you didn’t know – classes in PHP don’t define a strict interface, and are open to change by subclasses:
NOTE: if you have strict errors enabled, you would get one…
In the above example we changed the credit method signature by adding a second required parameter. We can now pass instances of SomeAccount class everywhere the BankAccount is expected and get nice fatal errors. Only interfaces and abstract classes/methods lock method signatures.
Please note that in the example interface, I don’t specify method visibility. The reason is every method of the interface MUST be public and no explicit visibility means public in PHP.
A class like the one above would cause a fatal error to be thrown: “Declaration of SomeAccount::credit() must be compatible with that of BankAccountInterface::credit()” or “Declaration of SomeAccount::credit() must be compatible with that of BankAccount::credit()”, depending on which approach you chose to use. If someone wanted to implement a BankAccount to be used with our PaymentGateway, they would have to keep the method signatures exactly the same as we defined them.
Hi everyone, in case you didn’t know – there was a ZendCon last Monday November 1st through Friday November 5th, 2010 in Santa Clara, California and most importantly – I got to attend and OpenSky sponsored my trip.
ZendCon is an annual conference organized by Zend the PHP company and held in California. Its known to be one of the biggest conferences in PHP world with attendees from all over the world varying from developers to top management, all using and interested in PHP. Zend makes PHP announcements – this year among other things, they announced that memory footprint of PHP had been reduced by 35% in the upcoming version – which are then followed up by different session from speakers from all over the world. These sessions vary in scope and context from detailed practical “how to”s of a framework or tool, to high level management advices and experiences.
As I already mentioned, this year I was thrilled to be among ZendCon attendees!
I arrived in Santa Clara on the evening of November 1st. This was my very first visit to west coast and I loved it. The first thing I saw when arrived at Santa Clara (after a 6 hour flight and a 2 hour ride on three trains – one of which had two levels) was a big Yahoo sign on one of the buildings which immediately felt like technology heaven.
During the next three days, I met interesting people from all over the world, including people I knew from twitter, but never met in person. I would like to especially thank Ryan Weaver and Pablo Godel, who are seasoned conference attendees, for making a great company and helping me get accustomed to the environment and people at the conference. I also met and spent a decent amount of time with people as: Jonathan Wage, Fabien Potencier, Nils Aderman, Dustin Whitle, Michelangelo van Dam, Jeremy Kendall and many many others.
I learned about Zend Uncon from Michelangelo during continental breakfast of the very first day of the main conference. Turns out that anyone could give a talk, even if it wasn’t included into the main session program. This is called the Uncon and there you can give a talk, do an interactive tutorial or round table on any topic you choose, all you need is to put your name in an empty slot in the Uncon schedule. Uncon sounded like a great idea and a good public speaking practice, so I registered… The session was amazing! Twitter was blown by quotations from my talk - tweeted, retweeted and re-retweeted. Attendees took pictures of me speaking and posted it on twitter too. Overall I was blown away by the success of my little experiment. As a result, my session was called the best Uncon session and I won a free lifetime license for Zend Studio 8 (they even wanted to call me up on stage during the final keynote, but I had a plane to catch that day).
Jonathan Wage, who joined OpenSky on the November 1st, 2010, suffered from poor organization on the conference part. He was unfortunate to get scheduled to arrive after his first session and leave before the second one. As a result, he gave only one talk of the two planned as part of the Uncon. His talk was, however, really amazing and well received by attendees and they wouldn’t let him go for a good 30 minutes after the talk was over, asking questions and expressing admiration.
Thank you ZendCon and see you again next year! Below are some pictures I took at the conference:
Unit testing is all about testing one piece of functionality in isolation. This is very easy when the subject of your test doesn’t involve any dependencies. Take the following method:
Unit testing is all about testing one piece of functionality in isolation. This is very easy when the subject of your test doesn’t involve any dependencies. Take the following method:
<?php
class Tag
{
public function normalizeName($name)
{
$normal = trim($name);
$normal = strtolower($normal);
return $normal;
}
}
Testing this method requires just an input and an expected output. This is a good case for using a PHPUnit dataProvider:
<?php
class TagTest extends PHPUnit_Framework_TestCase
{
/**
* @covers Tag::normalizeName
* @dataProvider provideNormalizeName
*/
public function testNormalizeName($input, $expected)
{
$tag = new Tag();
$this->assertEquals($expected, $tag->normalizeName($input));
}
public function provideNormalizeName()
{
return array(
array('foo', 'foo'),
array('FOO', 'foo'),
array(' foo ', 'foo'),
array(' FOO ', 'foo'),
);
}
}
Unfortunately, it’s not always this easy. Let’s say we want to centralize this normalization logic in some sort of reusable Normalizer class, which we inject into the Tag class:
<?php
class Tag
{
protected $normalizer;
public function __construct(Normalizer $normalizer)
{
$this->normalizer = $normalizer;
}
public function normalizeName($name)
{
return $this->normalizer->normalize($name);
}
}
The test above still passes, but we are now testing two things: the normalizeTag method and the Normalizer class; we are no longer testing our method in isolation.
Mock objects to the rescue!
To restore this isolation we create a “mock” version of the Normalizer class and tell that mock exactly what we expect will be done to it and how we want it to respond.
In PHPUnit 3.4, creating this mock object would look something like this:
<?php
class TagTest extends PHPUnit_Framework_TestCase
{
/**
* @covers Tag::normalizeName
*/
public function testNormalizeName()
{
$input = 'foo';
$expected = 'foo';
// the final "false" tells PHPUnit not to call the Normalizer
// constructor because it requires another dependency, which we don't
// care about right now
$normalizer = $this->getMock('Normalizer', array(), array(), '', false);
$normalizer
->expects($this->once())
->method('normalize')
->with($input)
->will($this->returnValue($expected));
$tag = new Tag($normalizer);
$this->assertEquals($expected, $tag->normalizeName($input));
}
}
Most of this is quite readable, thanks to Sebastian’s nice mocking API. However, the initial getMock method is a bit gnarly. I’ve added a comment so you understand what’s going on, which I’d rather not have to do.
In PHPUnit 3.5 we can use the new mock builder object, a contribution of Giorgio Sironi, which makes our test code that much more readable:
<?php
class TagTest extends PHPUnit_Framework_TestCase
{
/**
* @covers Tag::normalizeName
*/
public function testNormalizeName()
{
$input = 'foo';
$expected = 'foo';
$normalizer = $this->getMockBuilder('Normalizer')
->disableOriginalConstructor()
->getMock();
$normalizer
->expects($this->once())
->method('normalize')
->with($input)
->will($this->returnValue($expected));
$tag = new Tag($normalizer);
$this->assertEquals($expected, $tag->normalizeName($input));
}
}
So there you go: unit tests, mocking, and the new mock builder.
People that RSVPed for the last Symfony NYC Meetup know, that it got canceled. We are very sorry, but the meetup speaker got sick and couldn’t make it. He did promise to give his talk on ESI caching as soon as he feels better.
Meanwhile, the meetup was moved to this coming Thursday, October 28th, 2010. The new topic is “Unit Testing. A guide to writing clean, testable code, that will be easy to maintain and extend”. This will be the repeat of the talk I gave to the OpenSky tech team a month ago. I will cover topics like unit-testing, dependency injection, mock objects and ways to refactor your code.
If you haven’t yet, please RSVP for the meetup and more importantly, come to hear me speak on the topic.
Edit: I uploaded the slides from that talk to SlideShare and embedded them below
At OpenSky, we concentrate on programmers’ skills and ways to improve them a lot. As part of that, we have Fridays dedicated to skill improvement – we, programmers, are allowed to write blog posts, prepare presentations¸ educate others on what we learned, refactor/improve our code or simply go through and add tests where they are missing.
Last Friday was very special. I finally took the time (the whole weekend before that) and put together some slides to give a long requested talk on unit-testing and the art of programming.
I wanted to cover as many aspects of testing and OOP in general as I possibly could, while preserving the structure of test-oriented talk, without concentrating too much on any single area.
I had no idea how to accomplish that when I started. However, the introduction section had given me a good understanding of how to relate all the different aspects, so it didn’t feel like I was jumping from topic to topic, not covering each in enough detail. I structured the talk around the properties of unit test – the properties we want to achieve in order to practice unit-testing. As a result of that, I was able to cover Dependency Injection (with the Law Of Demeter as a natural consequence), Mock Objects (leading me to Iterative Interface Discovery and Test Driven Development) and some general OOP techniques, that let programmers achieve much desired code clarity (Inheritance instead of Conditionals and Composition over Inheritance).
Ideas promoted in the talk were inspired by a number of different sources, and I feel I should list the references, since they were not included in the slides:
The talk turned out to be pretty good and I received a lot of positive feedback on it from outside after posting it on slideshare. Even though I reserved 90 minutes to cover everything and answer all the questions, I was not able to do so, since we started later than planned. Therefore, I’m sharing the talk here and if anyone has questions or comments after watching the slides, feel free to post them here.
Some of you might, others might not know that our company, OpenSky, became the official sponsor of Symfony NYC Meetups, which means, that we’ll be seeing you the last Thursday of every month, here, at OpenSky HQ in NYC for the foreseeable future.
That was enough of the introduction, now to the point. Last Thursday, September 23rd, 2010, OpenSky held its first Symfony NYC Meetup. And, as anything OpenSky does, the Meetup turned out amazing. Our very own Kris Wallsmith gave an awesome talk, highlighting the differences between symfony 1.x and Symfony2. This was particularly useful, since my co-workers are the only people I know in NYC using Symfony2, and the majority of Meetup attendees are still in symfony 1.x world and hesitate to switch.
During the second, less structured part of the Meetup, we were enjoying pizza, that OpenSky kindly provided, discussing Symfony2 feature roadmap, current limitations of certain components and proceeded to other interesting, but hardly Symfony2 related topics like NodeJS, Android OS, Document-Oriented Databases (CouchDB and MongoDB) and PHP 5.3 Object Document Mappers (Doctrine MongoDB ODM and Doctrine CouchDB ODM).
In general it was a very interesting event and I feel sorry for those who couldn’t attend.
Since this is definitely not the last Meetup OpenSky is hosting, make sure to come in next time, to meet fellow symfony developers, share ideas and get to know OpenSky.
As a bonus, here is Kris’s video, where he talks about Symfony2.
The core symfony 2 team has just released Symfony 2 Preview Release 3. Of the 50+ different contributors, OpenSky provided 5 of them. Our developers contributed meaningful code commits which the core team approved and integrated with the release. We are excited to be a part of this thriving community and to be able to both use and contribute to such an excellent framework.
Here is a list of our team members and their commit counts towards this release:
This article was written by Matthew Fitzgerald, Software Engineer, and Mike Zupan, Systems Engineer at OpenSky
The fix will go live next week (Sept 29)
One of the most important ways Shoppers find Sellers is through Search. Recently, we’ve found a hole in our search index. The problem we had was, Sellers would select Products with keywords like “beauty” in the Product Name but that Seller would not show up in the Search results for “beauty”.
The reason for this was our Seller search index only had direct information on the Seller, ie: Seller Username, Business Name, Bio, etc… The Seller index had no knowledge of Products the Seller was promoting. So any keywords the Product might have, wouldn’t return the seller in a search.
The Solution
We needed to modify our Seller index to have knowledge of both Products and Sellers and return the results of distinct sellers. The problem, our current Search technology (SOLR) didn’t support that behavior of Grouping Product Records by Seller and collapsing them into distinct Seller results.
The Tech Part
After some hefty Googling, I found that the feature to Group Search results does exist in a future version of the technology yet to be released. This feature became so popular that the developers of our Search technology released a “patch” to include this feature in the current version of the software. This is how I applied the patch.
Step 1
If you are like me, you hate Subversion and you love GIT. I run Ubuntu and using apt-get I installed a git subversion bridge.
sudo apt-get install git-svn
Step 2
Get some reading material, then start the checkout the latest stable tag of Solr
If you’ve ever used the Internet (how else are you reading this?), then you have used a search engine. Search powers everything from shopping to dating to research, and is so common that people use it without thinking about it… it is just natural.
Of course, when something is natural, you expect a comfortable experience and a good fit. You probably don’t wake up in the morning and put on someone else’s clothes; instead, you probably have a wardrobe of comfortable apparel that you piece together a look that feels good and feels right.
We don’t feel this is how our search experience at OpenSky has been. If you wanted to find products, you could get to them pretty well. But if you were a seller trying to find a great supplier to connect with, the experience was… lacking? discombobulated? Not cohesive, at any rate.
So we decided it was time to roll our own search experience rather than let our community search continue to be powered by [insert ginormous search engine]. Here is how we did it.
Search Technology
We use Apache Solr to power our custom searches. Solr is a search platform that utilizes the popular Lucene search library as its core, is blazing fast, and is open-source… hey, we like open source projects around here.
We decided to create a new Solr index for indexing and searching community data, rather than create a unified index for searching all data, the primary reasons being variance in relevant data fields and the ability to apply the unique schema to do more complex, targeted, and nifty search applications that we haven’t thought up yet.
There are certainly some benefits that can be gained from having a unified index, and we are currently cooking up some things which will make use of both unified and specific indexes, so we can make our search experience as useful and intuitive as possible. Expect more great things coming up as search continues to evolve.
Schema Considerations
Careful thought and consideration went into how we designed the schema. We are using the DisMax Query Parser for our general search, and one of the things we learned that hard way is that inconsistent field configuration options, such as stopwords or other tokenizer index / query filters, can seriously affect query results. Also, it pays off to tweak some default configuration options to your needs.
As a concrete example, the DisMax Query Parser defaults to requiring all search terms to be present in a field to generate a positive hit. Assume you have a document with title = “Essence of murtlap”, description = “Essence of murtlap is phenomenal!”
Assume title is a “string” field with no tokenizer filters defined, while description is a “text” field with a stopwords configuration that prevents “of” from being tokenized, as it has high frequency and low importance.
In this case, a search for “Essence of murtlap” will not return any results. Why? Since “of” was not tokenized in the description field, 100% of the terms do not match, and so the entire document is a negative hit. However, searching for “Essence murtlap” would match. This may seem odd — after all, 100% of the terms DID match in the title field. For a mor thorough explanation, see one of severalavailableresources.
I also decided to throw a tokenizer filter to remove leading and trailing punctuation. The inspiration for this was trying to match a word at the end of a sentence. Using the same example above, one would expect to be able to have a positive hit by searching for “phenomenal” — but one would be mistaken. Without some TLC the actual token stored is “phenomenal!” so, unless you include that punctuation in your search, you are going to be disappointed.
Fortunately, I found a very useful thread which presented a simple way to solve the problem using regular expression string filtering while indexing the document:
If you decide to use Solr to facilitate your next searching project, don’t be afraid to get your hands dirty and play with the schema configuration. Solr has a lot of good documentation, is extremely powerful, and isn’t nearly as scary as it seems.
In the meantime, enjoy the new unified search experience and keep looking for more great things to come.