Olivine is a .NET (and Java and Objective C to a lesser extent) inspired PHP class library that attempts to provide useful types for PHP.

Motivation

PHP is an unplanned language that was developed in a more-or-less ad-hoc fashion. As a result, PHP did not gain a useful object system until PHP 5. So, even though PHP has things like classes, inheritance, data-hiding, namespaces and other goodies that you'd find in languages like C# and Java, it doesn't really make use of them in the standard API.

Olivine attempts to fill that gap by implementing an API, inspired by the .NET framework, that wraps many of the built-in PHP functions.

Let the Examples Do The Talking

Olivine is best demonstrated in examples. Consider this C# code:

var str = "I am a long, long string";
str.StartsWith("I am"); // true
str.Reverse().EndsWith("ma I"); // true

This can be easily transcoded to Olivine like this:

$str = is("I am a long, long string");
$str->startsWith("I am"); // true
$str->reverse()->endsWith("I"); // true

You're probably wondering what all the is() function calls are for. They're there to wrap the PHP types to the Olivine types. Olivine provides many of the .NET types you know and love like String and Boolean. In Olivine they are known as NString and NBoolean. Here's how you instantiate an Olivine NString type without using is().

$str1 = NString::get("Apple");
$str2 = is("Apple");
$str1->equals($str2); // true
$str1->equals("Apple"); // true

What about Int32, Int64, Single, Double and the other number structures? Olivine provides two numeric types: NInt and NFloat. They wrap the PHP primitives int and float.

$num1 = NNumber::get(4);
$num2 = is(5);
$num1->isLessThan($num2); // true

$num3 = _int(3);
$num1->isGreaterThan($num3); // true

You're probably wondering why we used _int() instead of is(). This was purely for demonstrative reasons. is() is smart enough to determine what Olivine type you want based on the argument type, as shown in this mapping:

is() Mapping
PHP Type (argument) Olivine Type (returned)
int NInt
float NFloat
bool NBoolean
string NString

In addition to is(), Olivine provides 5 functions that wrap the ::get() calls of the 5 main Olivine value types.

Olivine Type Aliases
Alias Olivine Type
_object() NObject
_int( int value ) NInt
_float( float value ) NFloat
_bool( bool value ) NBoolean
_string( string value ) NString

What are the advantages?

Why bother with Olivine at all, you ask? Here are a couple reasons:

  1. A tried and true object-oriented API inspired by the .NET framework. No longer will you have to fish around in the PHP manual looking for the function you need — they'll all appear when you press Ctrl-Space after an Olivine type.
  2. Method chaining. Instead of having do stuff like strtoupper(substr($str, 0, 10)) you can do $str->substring(0, 10)->toUpper(). This allows you to write code faster (as you don't have to backtrack when chaining) that is also easier to read.
  3. Knowledge reuse. If you already know the .NET API, you already know Olivine. All that time you spent programming in C# and Visual Basic can be translated to PHP quickly.

Olivine is also completely compatible with existing PHP code. If you want to use an NString with an existing PHP method that is expecting a regular string, you can simply access the underlying value using the methods provided by the IConvertible interface. For example:

$str = is( ... lots and lots of text ... );
$wrapped = wordwrap( $str->string() );

Drawbacks

Olivine isn't perfect, nor is it the solution to every problem you'll encounter in PHP. Specifically, Olivine has the following known drawbacks:

  • Overhead. Olivine has a .NET inspired type hierarchy that requires more resources than just using the primitive PHP types.
  • Incompleteness. Currently, Olivine only implements NString, NBoolean, NNumber, parts of Math, and a handful of interfaces. Most glaringly, Olivine currently does not implement the System.Collections API. This will be needed in order to complete the NString class (specifically things like split and join operations).
  • NNumber is probably slow. NNumber currently wraps function calls to the BCMath arbitrary precision library the ships with PHP. This is probably much slower than the built-in ints and floats. This will hopefully be remedied in the future by having NNumber choose its underlying type based on if it can fit in an int, float or BCMath container. For performance and simplicity, Olivine now provides NInt and NFloat instead of a unified NNumber class.
  • Boxing. Having to box every literal that you pass to a method with is() is tedious and obfuscates the code. Perhaps making all Olivine types auto-box primitive types might be a good idea. For example, if you write $str->replace("foo", "bar"), Olivine could automatically box "foo" and "bar" into NString types. Olivine now has auto-boxing. That is, anywhere you can pass an NString, you can pass a regular string equivalent. Same goes for NBoolean and NNumber.

What Needs to be Done?

More on this after the first release.