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.
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
$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:
|PHP Type (argument)||Olivine Type (returned)|
In addition to
is(), Olivine provides 5 functions that wrap the
::get() calls of the 5 main Olivine value types.
|Olivine Type Aliases|
What are the advantages?
Why bother with Olivine at all, you ask? Here are a couple reasons:
- 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.
- 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.
- 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() );
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 withOlivine 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.
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.
What Needs to be Done?
More on this after the first release.