Deprecated: Assigning the return value of new by reference is deprecated in /homepages/32/d230485870/htdocs/jessmann/blog/wp-settings.php on line 520

Deprecated: Assigning the return value of new by reference is deprecated in /homepages/32/d230485870/htdocs/jessmann/blog/wp-settings.php on line 535

Deprecated: Assigning the return value of new by reference is deprecated in /homepages/32/d230485870/htdocs/jessmann/blog/wp-settings.php on line 542

Deprecated: Assigning the return value of new by reference is deprecated in /homepages/32/d230485870/htdocs/jessmann/blog/wp-settings.php on line 578

Deprecated: Function set_magic_quotes_runtime() is deprecated in /homepages/32/d230485870/htdocs/jessmann/blog/wp-settings.php on line 18

Strict Standards: Declaration of Walker_Page::start_lvl() should be compatible with Walker::start_lvl(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1199

Strict Standards: Declaration of Walker_Page::end_lvl() should be compatible with Walker::end_lvl(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1199

Strict Standards: Declaration of Walker_Page::start_el() should be compatible with Walker::start_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1199

Strict Standards: Declaration of Walker_Page::end_el() should be compatible with Walker::end_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1199

Strict Standards: Declaration of Walker_PageDropdown::start_el() should be compatible with Walker::start_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1244

Strict Standards: Declaration of Walker_Category::start_lvl() should be compatible with Walker::start_lvl(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1391

Strict Standards: Declaration of Walker_Category::end_lvl() should be compatible with Walker::end_lvl(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1391

Strict Standards: Declaration of Walker_Category::start_el() should be compatible with Walker::start_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1391

Strict Standards: Declaration of Walker_Category::end_el() should be compatible with Walker::end_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1391

Strict Standards: Declaration of Walker_CategoryDropdown::start_el() should be compatible with Walker::start_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/classes.php on line 1442

Strict Standards: Redefining already defined constructor for class wpdb in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/wp-db.php on line 306

Strict Standards: Redefining already defined constructor for class WP_Object_Cache in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/cache.php on line 431

Strict Standards: Declaration of Walker_Comment::start_lvl() should be compatible with Walker::start_lvl(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/comment-template.php on line 1266

Strict Standards: Declaration of Walker_Comment::end_lvl() should be compatible with Walker::end_lvl(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/comment-template.php on line 1266

Strict Standards: Declaration of Walker_Comment::start_el() should be compatible with Walker::start_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/comment-template.php on line 1266

Strict Standards: Declaration of Walker_Comment::end_el() should be compatible with Walker::end_el(&$output) in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/comment-template.php on line 1266

Strict Standards: Redefining already defined constructor for class WP_Dependencies in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/class.wp-dependencies.php on line 31

Strict Standards: Redefining already defined constructor for class WP_Http in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/http.php on line 61

Strict Standards: call_user_func_array() expects parameter 1 to be a valid callback, non-static method GoogleSitemapGenerator::Enable() should not be called statically in /homepages/32/d230485870/htdocs/jessmann/blog/wp-includes/plugin.php on line 339
Jess Mann » Blog Archive » My complaints with PHP -

My complaints with PHP

Class constants:
You should be able to assign function return values and arithmetic operations to class constants. Constants have a unique use which can’t be filled by other variables without jumping through a whole bunch of hoops, and limiting their use so drastically is a problem. Also, the workaround is unacceptable:

define('someConstant',someOperation());
class Foo {
    const myConstant = someConstant;

Getting the value of a class constant with a dynamic name should be a LOT easier. The current solution within the class is:

return @constant(get_class($this).'::'.$constantName);

I’m sorry, but this is absurd. I shouldn’t have to call 2 functions, concatenate three strings AND suppress errors just to get a constant’s value. Plus, could this look more ugly?

Also, I should be able to define private and protected class constants:

private const myConst = 1;      //error

Static Variables and Methods
Static methods and variables should be accessible in the same way as their non-static peers. A big part of OOP is abstraction, and the whole point of an abstraction layer is not knowing (or caring) what exact class an object is (so long as you know what it inherits from). Not being able to access static methods without knowing the className makes just another hoop for the developer to jump through to access a class’s properties. As it is, I now have to set a throwaway variable just to call my method:

$className = get_name($object);
$className::method();

Also, in my development, I commonly make a library of classes I use elsewhere throughout the application, and then go on to making application-specific code which uses that library. As the “application developer”, using the library, I should not have to know the ins-and-outs of each variable and method each object has. What do I care if “getName()” returns the same name for each instance of the class, so long as it returns the name of the object I’m dealing with? As long as I call the method as described, and get the value I want, I shouldn’t have to worry about whether it’s static or not. I should be able to do this:

$object->staticMethod();

Furthermore, this becomes a major problem with any kind of semi-complex calling of methods. Namely, suppose we define 2 methods for an object: “void load(array)” and “array unload()”. load() takes an array, and for each key (’name’), checks if a public variable “$name”, or a public method “setName” exists, and if so, sets the value. Unload does the opposite, retrieving every public variable and getter method and returning it as an array. Our load and unload methods couldn’t care less how the variables are defined, just so long as they are defined… nor, I’m sure, do the methods calling load or unload care about the class’s implementation. It only cares about the data. But, to properly handle all this functionality, an extra 5 or so lines of juggling with PHP’s reflection classes is necessary, and for what benefit?

Chaining Methods and Passing Return Values
This probably wouldn’t be so much of a problem if it weren’t for the other issues, but I should always be able to chain the returned object (or className) from one function call with one of its methods:

get_class('foo')::variable; //error

And I should also always be able to pass the return value from a function as a parameter:

empty(foo());                //generates a fatal error
implode('',func_get_args()); //another error
array('1','2')[1];           //parse error

This actually does come up a lot for me. And by a lot, I mean around once a month I have to set a throwaway variable just to check, modify or use a function’s return value, or to perform some other operation I should be able to chain. It’s annoying. I understand the basic reasoning behind it, but that doesn’t make it any less annoying. In combination with the slew of other “minor” issues, it makes my code a lot more convoluted and complex than it really needs to be.

call_user_func
call_user_func is not a reasonable solution to these problems. call_user_func is messy, ugly, and time consuming. In fact, to be completely honest, call_user_func really shouldn’t exist. If you know the name of a function, you should be able to call it. There shouldn’t be an instance when you can’t because of some limitation of the language, such that you have to resort to calling some hack function to call some other function you can’t get to.

Abstract classes vs. Interfaces
Abstract classes should work identically to a combination of a non-abstract class and an interface. It allows the definition of complete class variables and methods (like a non-abstract class), and the definition of abstract variables and methods to be later defined in children (like an interface). So, why then, is it not able to define “abstract static” class variables or methods, when an interface can do just that? The following will work in an interface, but not an abstract class:

public abstract static function foo();

So, if I want an abstract class which requires its children to define a static method, I have to create another full interface (which is implemented only coupled with the abstract class) just to do it, even if the interface serves no other purpose but to do the one thing the abstract class should have been able to.

Method Overloading
Overloading class methods is extremely limited. Not only is there functionality missing I’d really like to see, but functionality you’d expect is also gone.

For example, one of my biggest annoyances is that methods with type hinting cannot be overloaded with type hints from child classes. For example:

class Foo {
    public function test( Foo $x ) { }
}
class Bar extends Foo {
    public function test( Bar $x ) { }
}

The above code is not allowed, and will throw an error. Why? Bar::test still requires an instance of Foo, which conforms to Foo’s interface, however, it -also- requires that the Foo object be a Bar. To properly handle this code, I have to define Bar::test in this way:

public function test( Foo $x ) {
    if (!$x instanceof Bar) {
        throw new Exception();
    }
} 

…Is it just me, or was type hinting added to -avoid- that sort of code?  Why typehint at all if I’m going to have to check instanceof later on anyway?

Also, python’s ability to reference parameters based on name is very nice. PHP doesn’t have this, in favor of pulling all the passed parameters and iterating over them to retrieve the one expected. Unfortunately, since PHP also doesn’t support method overloading in the “normal” way, by defining multiple methods (and I fully understand why), the developer is forced to create monstrosities like this:

public function create_image( $name, $id, $class, $type, $value, $url, $posx, $posy, $container, $style, $width, $height................ 
...
$this->create_image('bar',null,null,null,null,'http://example.com/bar.gif',null,null,null,null,150);

Or, to define multiple functions with mutliple names all serving a single purpose:

public function create_image( $name, $url ) { }
public function create_image_xy ( $name, $url, $posx, $posy ) { }
public function create_image_in_container ( $name, $url, $container ) { }

This is equally annoying. (NOTE: The above would be handled best with a full class and multiple method calls, but oftentimes this isn’t similarly possible). Since we have type hinting, it would be nice to also support Java’s way of method overloading:

public function create_image( $name, Lib_Url $url ) { }
public function create_image( $name, Lib_Container $container ) { }
...
$this->create_image('bar',$container_obj);

Or python’s way of calling a method with a different parameter order:

$this->create_image('name'=>'bar','url'=>'http://example.com/bar.gif');
//OR the usual way with no names
$this->create_image('bar');
//OR the messy way with no names and nulls
$this->create_image('bar',null,null,null,null,'http://example.com/bar.gif'); 

Sure, this can be done by accepting just an array, and processing the variables in any order there, but then you have to define code for default values, type hinting, required parameters, and so on (which could be 20 lines of unnecessary code)… and you force the application developer to create an array to pass in, which is similarly inconvenient.

Is this absolutely necessary? Probably not. But, PHP is still an immature language in my mind, and things like this are precisely why.

Incomplete Features
I have to say there are a few features not in PHP that I’d really like to see as well… For one, multiple inheritance would be really nice. Yes, other “safe” languages like Java don’t have multiple inheritance, but so what? Languages like Java don’t -need- multiple inheritance because of the way they are structured.

The problem with PHP is that it is structured in such a way as to encourage a developer to create a standard library for reuse in different applications. When you know PHP… it just seems natural to do this (and I’m not alone in this feeling. Check out the multitude of frameworks for PHP, including Zend Framework, Cake PHP, Symfony, or the 30-some other popular ones listed on wikipedia). Additionally, PHP defines classes from all over the place, from the SPL, to additional frameworks and extentions, to custom classes you’ve created, how are you expected to integrate each of these while still managing to reuse code? You aren’t.

In creating a library, common practice in PHP is to have each element of the library extend other elements of the same library. In that way, you can do things like:

catch (library_exception $e)
if ($obj instanceof library_object)
class New_Class extends Library_Base

…and so on.  It’s extremely useful to do things in this way… however, it also limits the developer to only using his code. Since my library is structured as above, I can’t use any other framework’s code, or the SPL. If I want to, then the class will no longer be considered a part of my library, and it won’t inherit my standard custom code… both of those are unacceptable, so I have to just live without the SPL. I shouldn’t have to do that.

Just the other week I was adding a file handler class to my library, which needed a bit of custom code to properly handle images in different formats, and such. I had to completely reimplement all of the SplImageObject class to do that. Argh! If I know what I’m doing, I should be able to use multiple inheritance properly. There’s a line between being “safe” and being restrictive.

Also, __toString is great. Really, the magic methods that exist for objects in PHP are awesome. However, __toInt would be a nice addition. Suppose I have an “Id” class, whose primary purpose is to store the (int) id of an object. Casting to an int should naturally return the ‘id’ value, such that performing comparisons (ordering, computing, etc) would be possible without having to define and call a separate getId() method, in other words allowing me to pass around the $id variable as though it were a primitive int, but have the benefit of the extra functionality the class defined:

$id->someOperation();
if ($id > 5)

It should be noted that I use PHP on a daily basis… and I like the language overall. However, it does have a number of caveats and issues which I really do think need to be addressed for it to avoid being overcome by the next hot language with all the features it’s missing. (Python is coming up nowadays, who knows?).

-Jess

2 Comments

  1. Rubin Labrada says:

    This is a smart blog. I mean it. You have so much knowledge about this issue, and so much passion. You also know how to make people rally behind it, obviously from the responses. Youve got a design here thats not too flashy, but makes a statement as big as what youre saying. Great job, indeed.

  2. Dereus says:

    I came across your webpage from twitter and it really is pretty informative. Thanks for discussing this kind of an incredible article.

Leave a Reply