Viability of PHP Legacy Wrapper Library

EDIT: Geez, I could have really gone with a better title for this topic.

Hi all,

One of my biggest gripes with PHP compared to just about every other language out there, is it’s incredibly inconsistent, ugly and non-object-orientated API. As an example, the available PHP string functions such as strstr(), str_pos(), str_replace(), and so on, are inconsistent not only in how they’re named, but also in argument order and sometimes behaviour. Then you have PHP libraries such as curl, fopen and anything else that uses “resources”, which are simply begging to be implemented as classes.

I’m thinking of developing an open-source PHP library, written in PHP, which wraps many of the legacy-style PHP functions into simple, elegant and powerful objects. This library, in addition to wrapping legacy procedural functions into a logical set of objects, could also make use of namespaces; something which no built-in PHP library or extension currently makes use of.

Let’s face it, as much as PHP’s API’s need a complete overhaul in order to keep up with the rapidly changing language, it’s not going to happen any time soon. In the mean time, I’m wondering if developers would be willing to sacrifice a relatively small bit of performance by using such as wrapper library to speed up development times, potentially reduce bugs, and most importantly, make PHP a nicer language to work in.

So I’ve started this topic simply to get a general opinion from those who spend a lot of time programming with PHP, and more specifically, PHP 5.2 and 5.3? Additionally, do you think it would be worth focusing on PHP 5.3 compatibility only, in order to make use of namespaces and other modern PHP features, and to act as a further incentive for people and ultimately hosting companies to move to PHP 5.3?

By the way, if I were to commit to such a project, rest assured that I’m a bit of a perfectionist, so would likely spend most my time planning and designing the API to make it as nice as possible; think jQuery-esque.

It’s a nice idea for the extensions. I do this anyway. I made classes for curl, gd and FTP (and others i’m probably forgetting).

I attempted to make a string object, but gave up due to php not really being powerful enough to give you enough control.

The first major hurdle is string comparison


class String {
	private $str;
	
	public function __construct($str) {
		$this->str = $str;
	}
	
	public function __toString() {
		return $this->str;
	}
}

$str1 = new String('Test');
$str2 = new String('Test');

//Evaluates to true because all the properties on both objects are the same
if ($str1 == $str2) echo 'equal';
else echo 'Not Equal';
		
//Evaluates to false
if ($str1 === $str2) echo 'equal';
else echo 'Not Equal';

Which works as expected, but will obviously will make === not work as you probably intended it.

Then, as soon as you add another property (such as an internal counter) to the class == breaks too.

Unfortunately php doesn’t support creation of infix functions like some languages. Which means you have no control over object comparison… and you’ll end up doing if ($str1->equals($str2)) which is ugly and if you need to do any manipulation of either string, very messy. E.g.


<?php
if ($str1->toLowerCase()->equals($str2->toLowerCase())) {
}
?>

The second big problem is that you have no way to automatically wrap all strings within the application, which means your application will be littered with $str = new String($str); before you can call $str->replace();

If you can overcome these issues I’d be happy to use your string class.

For now I’d just give the common extensions an OO interface.

Actually, I think that is expected and even desired behaviour. Testing for equality on object should return false if you’re not talking about two references to the same object. It would, indeed, be nice to be able to do operator overloading, but I think that is something that will never happen in PHP. I, personally, don’t have a huge issue with:


if( $string->lower( )->equals( $string2->lower( ) ) {
}

Fair enough, but that’s the price you have to pay. If it were me, I’d create helper functions to create more compact and concise code for this:


function _s( $string ) {
  return new String( $string );
}
$myString = _s( 'This is my string!' );

That directly solves the problem of transient strings:


if( _s( 'This string' )->equals( _s( 'This string' ) ) ) {
}

I’m much more concerned as to what will happen in you write a class called string. As far as I know, that’s a reserved class-name, as are all other data-types. Anyway, wardrop, if you are to pursue this, let me know, I’m interested, although I can see the troubles ahead as well.

I wouldn’t take the approach you took. You’ve tried to wrap the primitive string type into a string object, so you can implemented convenience methods found in most OO language which were born as OO languages. I personally wouldn’t do this, as in addition to some of the drawbacks you encountered, it’s not idiomatic to PHP. In other words, that’s not the PHP way.

Instead, what I’d probably do is create a static class. I’d probably avoid method chaining, as method chaining isn’t idiomatic to PHP. It would likely throw developers off. To put it a different way, my goal wouldn’t be to change how we write PHP, but rather improve how we access and use common procedural API’s. I’d use the same approach for the array API as I would for the string API. Those API’s which use resources however, will be the main one’s I’ll be targeting, as they’re the ones that are really begging to be turned into classes.

To give some examples…

String API


$title = String::lowerCase($title);
$title = String::upperCase($title);
$title = String::upperCaseWords($title);
$title = String::titleCase($title); // Has built-in smarts to do proper title cases, such as "The Story of the Year!", instead of "The Story Of The Year!" as upperCaseWords() would yield.
$title = String::replace("\\r\
", "\
");

File API


$file = new File('/tmp/myFile.txt');
$file->append("random data");
$file->appendLine("random data on a new line"); // Checks file for line break type.
$file->move('/uploads/myFile.txt');
$file->copy('/tmp/myFileCopy.txt');
$file->nextLine(); // Returns the next line of the file.
$file->next(1024); // Gets next 1024 bytes.

So while the String API would be mainly to create more readable and writeable code, the file API would also increase development speed by encapsulating the file “resource” in an object. All API’s however will include enhancements to allow more to be done with less code, such as the “titleCase()” method of the string API, and the “appendLine()” method of the File API.

While short names are desirable, ease of reading the code and learning the new API would be of higher importance.

I will definitely look into method chaining though for the String and Array API’s, to see if I can’t find a idiomatic of chaining together multiple method calls. Also keep in mind that these are only examples roughly demonstrating the desired outcome of this proposed project. I’d spend plenty of time identifying the best names for methods and classes, as well as the best way to use and interface with them.

The problem is, if you’re just renaming functions and swapping the parameters, it’s only really going to be useful to new developers :stuck_out_tongue: I know I’d use the original function names out of habit.

$title = String::replace("\r
", "
");

How does this know what it’s doing the replacement on?

@webaddictz, that really reduces code readability imho. Having a function called _s is at best confusing. If you’ve ever programmed in perl you’ll know how annoying random 2 letter function names are.

IMHO, there are certain cases where this type of enhancement is okay, and certain cases where it is not. I make a point specifically not to enhance or wrap any native type or existing built-in function, even if there are inconsistencies that annoy me. Making a custom String class will both confuse people who are used to the standard PHP functions and add extra code and overhead to your application. Strings are the most common native type. You don’t want all those objects being created for marginal benefit.

The Files example, on the other hand, is one that I myself would do also. It’s a more complex series of actions that there is no good built-in code to handle well. Making it an object also allows you to load and save the file to and from different sources by switching an adapter, like filesystem, Amazon S3, NoSQL key/value store, etc. so there is a clear and concrete benefit to writing that code that would not be possible or as concise and easy to read as using built-in functions. That’s the key difference. There has to be a very real and tangible benefit for writing the code.

It’s also funny that you mention jQuery, because that was my inspiration for making simple method APIs with method chaining as well. For instance, I came up with this RESTful router in my AppKernel project that I currently use in many live sites and other projects:


// Get AppKernel instance
$kernel = AppKernel();

// Get Router object
$router = $kernel->router();

// Setup REST Routes
$router->route('controller_item_action', '/<:controller>/<#item>/<:action>(.<:format>)')
	->defaults(array('format' => 'html'));

$router->route('controller_item', '/<:controller>/<#item>(.<:format>)')
	->defaults(array('action' => 'view', 'format' => 'html'))
	->get(array('action' => 'view'))
	->put(array('action' => 'put'))
	->delete(array('action' => 'delete'));

$router->route('controller_action', '/<:controller>/<:action>(.<:format>)')
	->defaults(array('format' => 'html'));

$router->route('controller', '/<:controller>(.<:format>)')
	->defaults(array('action' => 'index', 'format' => 'html'))
	->post(array('action' => 'post'));

It doesn’t; it generates a random string for you :P. No, I actually started thinking about something at that point, and ended up forgetting to pass it the string in the list of arguments. The string would have come first in the list of arguments just so you know.

I almost skipped over this line when I read your post, and was going to say that absolutely if you could do something like jquery for php, I would use it for sure.

The emphasis has to be on lightweight, wrapping up common functionality just like jquery does, with awesome documentation and endless addon possibilities.

The learning curve has to be very slight - the shortcuts have to be big. I have been programming in PHP for about 4 or 5 years, and I won’t even look at existing frameworks because they seem to want to control everything, and there is much to learn. The beauty of jquery is that you use only what you want, its flexible, and you can revert to plain old js whenever you want.

Based on what I re-use over and over again, I would vote on session management / user privileges, database, date, sanitation.

For the power users, perhaps a “standardized” MVC handler.

Thanks for the reply wheeler. Finally, someone who doesn’t think “method chaining” when they see or hear the word “jQuery”. PHP isn’t a method chaining language, it’s that simple. It should only be used where it makes absolute sense, which is normally in circumstances where any other method would drastically reduce simplicity or power; SimpleXML is a good example of such a circumstance.

Personally, when I think jQuery, I think of a tool that people, whether beginner or expert, simply can’t live without. Wheeler is certainly on the money. What he talks about is definitely what such a project as this one should be all about. Peel away the complexity and the “illusion” of flexibility, and provide a truly powerful, lightweight API for tackling the most common problems faced by PHP programmers, in exactly the same manner as jQuery addresses the most common problems faced by JavaScript programmers.

I’m not sure if my String or File API examples above would meet those goals; probably not as they are to be honest.

@Wardrop
hmm, i just deleted a wall of text.

in short:
minor/cosmetic changes and a new api to learn, won’t help anyone. come up with something that gives me an advantage.

I agree.

I would say talking the same language as other php developers would be a good start, the way that jquery developers have a platform from which they derive many solutions.

Because to be honest, when I read php posts in forums, they can be pretty much split between ideological sword fighting about very complicated OOP concepts, and very basic beginner questions.

The missing middle ground I think is something that saves time, is freely accessible and that developers from all levels can pick up and understand.

It sounds kindof silly as thats what plain old php should be, but like plain old javascript, its just not.

I guess it begs the question as to why nothing has become mainstream yet.

The string API above probably wouldn’t make it in. I was thinking String’s at the time because that’s where the discussion went initially.

My initial motivation for this library was just how crap the current PHP API is. But as you say, an API that only wraps existing functions 1:1 isn’t going to catch on, as it’s simply of little benefit. I think to make this library a success, it needs to provide something developers can’t live without, once they try it.

Achieving that won’t be simple, but that’s the goal.

Note, I have had a couple of drinks so I hope that makes sense.

that proves my assumption that you try to do something fancy just for the sake of it. don’t try it. you need a real problem to solve, otherwise you’ll go nuts or just waste time.

if the api inconsistencies annoy you, it’s a better way to write an RFC to correct them in php itself.

fopen() already works in an object oriented fashion (streams), though the calls may be procedural. They exhibit abstraction, encapsulation, and decoupling. Inheritance and polymorphism could be argued for, although they only apply to user-defined streams.

curl is a different matter. The API of that thing is terrible.

I agree that the primary benefit of jQuery isn’t method chaining, but I’m not sure why you think PHP isn’t a method chaining language, whatever that means. There are many cases where it makes sense and is really beneficial. Chaining works well in situations where there is one item that you have to add multiple settings or parameters to. URL routing, view templates, and query builders are where I use method chaining most, and PHP handles it very well. Of course it’s not applicable or even wanted in all situations - there is no silver bullet.

The reason I like jQuery so much is that it’s the only framework I know of that allows people who don’t even know the language to write code that works. It took a simple and intuitive approach to solving common development problems, and that’s why it was such a success and why it’s still so awesome. I agree that PHP needs the same thing, and I am currently working on many projects towards that goal. I like seeing that there are other people here who think the same thing.

I agree, the trendy name for method chaining is fluent interface. Any OOP language is a candidate for some method chaining if it enhances readability in that instance.

And is used in the mocking engine of phpunit
http://www.phpunit.de/manual/current/en/test-doubles.html#test-doubles.mock-objects


<?php
class SubjectTest extends PHPUnit_Framework_TestCase
{
    public function testObserversAreUpdated()
    {
        // Create a mock for the Observer class,
        // only mock the update() method.
        $observer = $this->getMock('Observer', array('update'));
 
        // Set up the expectation for the update() method
        // to be called only once and with the string 'something'
        // as its parameter.
        $observer->expects($this->once())
                 ->method('update')
                 ->with($this->equalTo('something'));
 
        // Create a Subject object and attach the mocked
        // Observer object to it.
        $subject = new Subject;
        $subject->attach($observer);
 
        // Call the doSomething() method on the $subject object
        // which we expect to call the mocked Observer object's
        // update() method with the string 'something'.
        $subject->doSomething();
    }
}
?>


The other day I added fluent interface to the mocking engine of an old version of simple test at work as removing visual duplication and the added indentation makes the tests much easier to read by allowing more effective visual grouping. It makes it not potentially not compatible with PHP4 but that is not an issue of us as all the php4 stuff is old phpunit. Have testing frameworks coming out my ears :wink:

Eg. SimpleTest without fluent interface
http://www.simpletest.org/en/mock_objects_documentation.html


    function testUserFinder() {
        $result = &new MockResultIterator();
        $result->setReturnValue('next', false);
        $result->setReturnValueAt(0, 'next', array(1, 'tom'));
        $result->setReturnValueAt(1, 'next', array(3, 'dick'));
        $result->setReturnValueAt(2, 'next', array(6, 'harry'));
        
        $connection = &new MockDatabaseConnection();
        $connection->setReturnValue('query', false);
        $connection->setReturnReference(
                'query',
                $result,
                array('select id, name from users'));
                
        $finder = &new UserFinder($connection);
        $this->assertIdentical(
                $finder->findNames(),
                array('tom', 'dick', 'harry'));
    }

In large tests it really makes the difference as the indentation changes of the -> are far easier to scan. I really was going blind up to that point by the fatness of it all.

What I meant by PHP not being a method chaining language, is that…

  • PHP types are not objects, they’re primitives, and cannot be easily boxed and unboxed like in languages such as Java. Method chaining is usually most powerful and/or useful on built-in types than on general objects.
  • The object operator in PHP is quite verbose, making it slightly less suitable for heavy use of method chaining. “->” requires 3 key presses on a standard US keyboard.
  • Method chaining is a technique rarely used in the native PHP library. SimpleXML is actually the only example I can think of off the top of my head. The native API of a language generally sets the standard for what is idiomatic, therefore, based on that philosophy, PHP, at least to me, is not a method chaining language.

By no means do those points above mean it shouldn’t be used, it just means that it should be used with care and should not be abused, as PHP isn’t a language as well suited to method chaining as many others. It’s likely that anyone who encounters method chaining (or a “fluid interface”) for the first time in PHP, even if they’ve seen the technique in other languages, it’s likely to throw them off. I know that SimpleXML took me a little while to get use to when a first encountered it.

It’s important to keep in mind though that JavaScript and PHP work in very different domains. Like how jQuery can be used with any other JavaScript framework, I think an important of goal of such a library/framework for PHP, would be to not implement any feature that enforces a certain application design on the developer. Unlike a traditional PHP framework which gives you a set of tools and boundaries to work within, such a project as this one would simply need to provide the set of tools, without pushing a certain application architecture or methodology. This project would have to be able to easily and seamlessly slot into any existing framework or project.