MacGDBp 1.5 Released

Posted on 2 September 2012, in MacGDBp. No Comments.Tags: , ,

MacGDBp 1.5 has been released. This update fixes a crash on 10.8 when adding a breakpoint. Credit for the fix goes to Paul Mitchell and Sam Fleming.

This release also includes a new feature that allows you to evaluate and see the result of an arbitrary PHP expression. For example, you can use print_r to get a different view of PHP objects:

Full details are in the changelog.

Tracking Info:
Current SHA1: 0508dff
Version: 1.5.0.104.0
Last Release Build: Sun Sep 2 21:13:38 EDT 2012

Bending PHP to Your Will

Posted on 6 August 2011, in Uncategorized. 2 Comments.Tags:

One of the best features of Objective-C is protocols. These are akin to PHP and Java interfaces, but have one huge advantage: you can mark certain methods as required or optional. This is useful in implementing the delegate pattern because if you do not care about a certain method, you can simply not implement that method. In PHP, this is not possible with interfaces: you must implement all the methods of an interface in order to implement the interface. While this is fine and makes sense in most cases, it’s not always convenient.

So I set off to find a way to create protocols in PHP. The language is fairly dynamic, so I was able to come up with a solution called WeakInterface. Before jumping into the implementation details, let’s see how it works in practice:

First you define your interface as you would normally:

interface AllOptionalInterface {
  public function DoSomething();
  public function DoSomething1(Closure $arg);
}

The class that implements this only cares about the DoSomething method, so it implements it:

class AllOptionalImpl {
  public function DoSomething() {
    echo 'I did something!';
  }
}

Note that this class isn’t said to implement this interface because it does not implement all the methods. Now in the code that is going to call this interface, you do the following:

$delegate = new WeakInterface('AllOptionalInterface');
$delegate->Bind(new AllOptionalImpl);
$delegate->DoSomething();
$delegate->DoSomething1(function() { echo 'Wow!'; });

This code will output “I did something!”. Let’s go line-by-line. First, $delegate is being created as an instance of WeakInterface, whose constructor takes the name of the interface to “implement.” Then the interface is bound to an instance of the implementation. And then finally two methods are called on the interface, and the one with an implementation is actually called. Calling DoSomething1() is a no-op.

I mentioned above that in Objective-C you can mark some methods as required, too. And that’s done with a docstring when using WeakInterfaces:

interface OneRequiredInterface {
  public function DoSomething();
  /** @required */
  public function DoAnything();
}

If you failed to implement DoAnything(), the call to WeakInterface::Bind() would throw an exception. But what if the number and type hints of the arguments of an implementation do not match that of the interface? WeakInterface has that base covered, too. Bind() will also check the parameters of all method implementations to make sure that the signatures match the interface’s.

That’s WeakInterface in a nutshell, but how does it actually work? It’s easiest to start with a callstack. So when $delegate->DoSomething() is called, this is how WeakInterface actually invokes the implementation:

# Time Memory Function Location
1 0.0033 975328 hoplite\base\WeakInterface->DoSomething( ) ../example.php:14
2 0.0033 975856 hoplite\base\WeakInterface->__call( ) ../weak_interface.php:0
3 0.0033 975856 hoplite\base\internal\MethodImp->Invoke( ) ../weak_interface.php:84
4 0.0033 976568 ReflectionMethod->invokeArgs( ) ../weak_interface.php:145
5 0.0033 976608 AllOptionalImpl->DoSomething( ) ../example.php:0

WeakInterface implements the magic PHP method __call(), which is invoked whenever a method call is performed and no method is found by the runtime. It captures this and then forwards the invocation on to an implementation helper MethodImp, which then uses reflection to finally invoke the proper implementation.

Going deeper, when a WeakInterface is constructed, the interface passed to it is reflected and the method list is walked. For each method, a MethodImp is created. When the WeakInterface is bound, that set of MethodImps is looped over, checking that any required methods are implemented and that any implementations match the interface’s method signature. At call time, the method name is looked up in the MethodImp table and the arguments are forwarded to the actual implementation.

One note on performance: due to the number of intermediate method calls, using WeakInterface is roughly four times slower than a plain method call. For most applications, this should not be significant at all; but for performance-critical code, you should steer away from WeakInterface.

The code is available here along with a unit test.

MacGDBp 1.4.1 Released

Posted on 28 April 2011, in MacGDBp. 5 Comments.Tags: , ,

MacGDBp 1.4.1 has been released; this is a maintenance update that fixes a few bugs. I meant to get this release out a few weeks ago, but I’ve been travelling recently and didn’t have the time.

You can download MacGDBp 1.4.1 from this page. Please file any new issues in the bug tracker.

Tracking Info:
Current SHA1: 7fde123
Version: 1.4.1.91.97
Last Release Build: 2011-04-29 00:33:16

MacGDBp 1.4 Released [u]

Posted on 26 February 2011, in MacGDBp. No Comments.Tags: ,

After a slight delay trying to track down some bugs, I’ve decided to push MacGDBp 1.4 to stable distribution. While this release is not quite perfect and there are a few known issues (listed on the project page), I was tired of blocking the release on relatively minor bugs. This release has been a year in the making, and it makes significant improvements over the 1.3 branch. To find out more about what went into making this new version, check out some of the older posts on the blog.

You can download MacGDBp 1.4 from this page. Please file any new issues in the bug tracker.

Update: A minor bug had to be fixed with the released package. I’ve pushed a new binary and the few people who have downloaded the update will be prompted to update again.

Tracking Info:
Current SHA1: 4ce0d31 d746f73e
Version: 1.4.0.85 .83
Last Release Build: 2011-02-26 14:21:17 2011-02-26 12:29:16

MacGDBp 1.4 Beta 2

Posted on 15 January 2011, in MacGDBp. No Comments.Tags: , ,

I’m happy to announce MacGDBp 1.4 Beta 2. It’s been nearly a month since the first beta was released and more than 200 people have tested Beta 1. I haven’t received any critical bug reports, which means that the internals are stable enough to ship. Beta 2 is the Release Candidate; barring any significant issues, this will be promoted to Stable in a month or less.

This release has a couple of bug fixes and adds two small enhancements:

You can download MacGDBp 1.4 Beta 2 from this page. Please file any new issues in the bug tracker.

Tracking Info:
Current SHA1: 5cfd0db
Version: 1.4.0.74 ß2
Last Release Build: 2011-01-14 23:48:03