

New to PHP 5.4: Traits - simast
http://simas.posterous.com/new-to-php-54-traits

======
agentultra
I don't understand the vernacular.

 _One of the noteworthy language additions are Traits – a brand new horizontal
code reuse mechanism._

Code re-use mechanism? Horizontal? I didn't realize PHP was so geometric. What
an interesting concept.

 _While traits are technically different from mixins – they are both designed
to fill the same gap left by a single-parent inheritance model_

So let me try and get this straight: mixins fill a gap left by a single-parent
inheritance model and so traits are like mixins because PHP has a single-
inheritance model but traits are technically different in some way?

This is getting confusing...

Python, Perl, Ruby, and many languages with multiple inheritance have been
using mixins for... well a long time. It's pretty straight forward.

Perl5 got "roles" through Moose and Perl6 has them natively. I think they're
explanations are a little more clear.
(<http://search.cpan.org/dist/Moose/lib/Moose/Manual/Roles.pod>)

 _As the original author of the patch Stefan Marr pointed out – traits are
nothing more but a compiler assisted copy and paste._

In true PHP fashion! What an interesting way to think about it.

 _Conflicts and Aliases_

Ok, this is pretty cool. It's an edge case, but there's already a solution.
Neat.

Oh... wait a second, I think I've found the meat of it:

 _Trait method definitions support all modifiers just like regular class
methods do – that includes visibility modifiers, final, static and abstract.
The latter can be used to define abstract methods expressing requirements for
this particular trait_

So this is how they're slightly different than regular-old classes? By being
able to use all the same keywords as regular old classes?

It seems that the meat of it is at the very end:

 _Traits only take part in the process of building a class and do not add any
new run-time semantics. That means that usual PHP object-oriented
functionality (like late static bindings) work as expected when combined with
traits._

But this next one is a bit of a gotcha:

 _Traits can be composed from other traits (the same way classes use traits)._

Wait... what? Why would you want to do this? You're just getting back into
hierarchies again... and pretty much just working around multiple-inheritance
without calling it such.

It's good to see PHP is evolving. Most people still think of PHP4 and shudder
(and rightfully so). Evolving means it might be catching up to the superior
languages it competes with in the web space. (Note the tongue-in-cheek).

I'm still not convinced, but it's a step forward I am sure for PHP programmers
everywhere. Just don't actually use trait-inheritance and you should be fine.

~~~
Nitramp
_I don't understand the vernacular._

It indeed seems like that ;-)

There are four concepts here:

* Multiple inheritance

* Interfaces (abstract types)

* Mixins

* Traits

Multiple inheritance is available in languages like C++ and Python. But
multiple inheritance has well known highly problematic side effects that
resolve around diamond inheritance and method aliasing. Basically you have a
directed graph of parent classes (with diamonds and all) all implementing a
foo() method, and then have to pick a method of linearizing that graph to find
out which method actually wins if someone calls o.foo(). There are multiple
solutions to that, but all are non-intuitive and have caused heaps of trouble.
It's just way to hard for a programmer to reason which method will be called
in his program.

This is why Java did away with multiple inheritance and just has interfaces. A
lot simpler, a lot cleaner, and easy to understand, but sadly lacking in
functionality.

The problem is supposed to be fixed by traits and mixins. I think there is no
really clean demarcation between the two. My understanding is that traits are
more or less mixins, but with the aliasing features and similar stuff you
highlight.

The _traits are nothing more but a compiler assisted copy and paste_ is
actually a feature, not a bug. This is exactly what you actually want to keep
your program understandable: the code/functionality from traits is effectively
treated as copied into your class, and there is exactly one "winner" in the
race to be the "foo()" method for this class, where the winner is determined
by things like aliasing, or order. All the weird situations where parent
classes call a method that is overridden in some branch of the inheritance
graph just don't occur.

So traits/mixins are IMHO a huge step forward from multiple inheritance or
just interfaces. Not that this will help with the mess that is PHP much ...

~~~
nickik
The best thing i have seen are clojures protocols. They are like interface++.
Check it out.

------
apinstein
I read about PHP's traits on the RFC system a few years back. Knowing Traits
and Closures were _coming soon_ was one of the main reasons I decided not to
bail for the ruby/python world.

To me traits are actually a _better_ solution than mixins via dynamism, since
you get syntax checking via the compiler along with the benefit of compiled
speed. You also have less confusion due to mixin conflicts.

I am _super_ excited about this. Thanks PHP!

------
AndrewO
It makes my skin crawl to see the first example use case be combining
inheriting from singleton and the array class. It looks like PHP is finally
getting advanced OOP features and the first thing someone wants to do with
them is make a singleton (which violate single responsibility, also
introducing global variables and tight coupling) that extends arrays (when
delegating to an array instance is usually a better choice).

I know this is a single example, but I feel like I've seen bad OOP practices
in PHP so many times in the past. This is such a rich feature but it brings
with it a lot of potential for misuse.

~~~
simast
What's wrong with singletons in general and why would an object could not
assume single responsibility (consider an UIApplication singleton on iOS)? I
thought, contrary to what you stated, they solve the issue of global variables
rather than introducing new ones.

That class extends SPL ArrayObject class which provides array-like access
syntax (operators). It does not mean it has to act like an in-memory array, it
could read data from disk, session, database or whatever. Delegating this kind
of functionality to a single array would simply not work without further
abstraction.

~~~
AndrewO
In addition to what the others said, these two pages make the arguments that
convinced me:

[http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140...](http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx)

<http://www.c2.com/cgi/wiki?SingletonsAreEvil>

I don't know the particulars of how PHP's ArrayObject works, but take Ruby for
example: instead of inheriting from Array, to make a class that operates like
an array, one mixes in the Enumerable module (similar to a trait) and
implements an "each" method to handle the low level access. All of the other
methods come along with the module. In this way, the lineage of a class isn't
important; rather, it's what it actually does that matters. (How meritocratic!
:-)

But particulars of any language aside, I think this is an important step for
PHP. Once a language gives the ability to compose the behavior of a class
through traits, modules, mixins, etc rather than standard inheritance, it
becomes easier to separate the data that a class encapsulates from the
behaviors that it provides—and that, I believe, leads to more modular code.

~~~
jamesbritt
"In this way, the lineage of a class isn't important; rather, it's what it
actually does that matters. (How meritocratic! :-)"

    
    
        In Ruby, no one cares who your parents were, all 
        they care about is if you know  what you are 
        talking about.
    
      - Logan Capaldo

------
tszming
5.3 => closure, 5.4 => traits, PHP's revolution?

Honestly, I would prefer PHP remove all the bad parts of PHP before adding new
things.

~~~
pilif
Do you know how long it took to finally get rid of PHP 4? Do you know how long
web hosters (and with that most open source projects targeting a wide
audience) were sticking with PHP4? Even now that there won't be any more php4
releases, there are STILL projects targeting PHP4. There are STILL webhosts
only providing support for PHP4. More than 5 years after PHP5 came out

All this even though most PHP4 scripts run _unaltered_ in php5.

And now you suggest to drop backwards compatibiliy to get rid of warts? How
long do you think it would take before that new language will get any
significant deployment? What good will all the new features be if you are not
able to use them in the next 10+ years?

Personally, I like to see them add features in a backwards compatible way.
Knowing PHP and programming in general, I can stay away of the bad parts but
still use all the new features in the foreseeable (2-3 years) future.

Just have a look at python3 of you want a taste if what you were just
suggesting.

~~~
tszming
I agree with you that incompatible changes by removing bad parts is definitely
painful, but it makes PHP more sustainable in long term.

This can happen in a more feasible way, e.g. freeze PHP5 (unlike the current
situation), don't add any new stuffs; branch out a subset of PHP (removing bad
parts), and continue the development there.

~~~
simast
Not sure of what kind of legacy features you would want to be removed but it's
not like they are just building on top without thinking.

PHP 5.4 will also drop:

\- safe mode

\- register_globals

\- allow_call_time_pass_reference/y2k_compliance and other legacy ini stuff

\- "continue 123" syntax (can be replaced with goto). As far as I recall this
is done since it's barely used and if removed would allow to implement some
opcode performance optimizations.

Dropping some PHP 4 era syntax is obviously out of question due to already
mentioned webhosting and backwards compatibility issues.

------
prodigal_erik
If it's just compiler-assisted copy and paste, users should have been able to
do it themselves rather than wait for the maintainers to add one instance of
compile-time code generation (out of many more which still aren't present)
that requires a platform reinstall to use. This is why languages should be
extensible via something like macros.

------
HerberthAmaral
So... do they figured it out how to fix the PHP's white screen of death? This
kind of thing is so annoying that I can't even think of using PHP in my future
projects.

~~~
cheald
I'd assume you'd mean segfaults. It's somewhat painful to track down a
segfault in PHP, but if you can compile PHP with debug symbols and then invoke
a failing scripts under gdb, it's fairly straightforward.

~~~
viraptor
Syntax errors, calls to @nonexistant_name(), and many others will simply
return an empty page and log the error to the error log (error is not
catchable, so you cannot even return anything sane to the user)

The fun starts when you hit one of the situations where the whole php
stacktrace is `in file "" at 0` (or something similar). I've got 4 php
programmers around me and I hear about the "white page" almost once a week, so
it's not that uncommon :(

~~~
wanderr
Bluesnowmonkey already gave you some specific solutions but I wanted to point
out that error suppression is generally a really bad idea. If your code
encounters an error you should want to know about it.

~~~
cheald
This is one of the reasons I really like working in Rails. An exception blows
the page up properly, and kicks into my exception notifier (sends me an email
with the environment and stacktrace) and can display an error to the user.
PHP's "soft on errors" approach is just a timebomb waiting to go off. "Fail
hard, fail fast" is less forgiving, but ultimately, helps me sleep a lot
better at night.

~~~
wanderr
PHP's behavior is configurable, it can be soft on errors or hard on errors.
Unfortunately many lazy developers choose the former.

~~~
cheald
I know that it blows up on fatal errors, and I know that you can have it
report or not report errors (error_reporting), but how would I, say, make it
terminate with a backtrace if I attempt to fopen a file that I don't have
permissions to open? The _proper_ behavior in PHP is to check your file
descriptors, but I'd much rather it just give up and go home, since behavior
after a failure like that is going to be unpredictable in many cases.

~~~
simast
I assume you are talking about fopen-type of functions that are nothing more
but wrappers around C standard library functionality.

Use SplFileObject (part of SPL that is part of PHP core) for object-oriented
way to manipulate files. On a failure (like your permission issue) it throws
Exceptions and if not handled this will result in a "hard" error with a
backtrace log.

~~~
cheald
Awesome, thank you. I'm a bit rusty on best practices since I've shifted my
focus away from php, but it's nice to know that options to make it behave a
bit more high level exist.

------
heimidal
At RubyConf last week, Matz (the creator of Ruby) introduced some of the ideas
that are being tossed around for Ruby 2.0. One of these is called
"refinements", and looks similar to what's being discussed in this article
when it comes to method conflict resolution.

Shudo Maeda, a colleague of Matz, went into greater detail about Refinements
in his talk. You can find the slides here: <http://slidesha.re/9rbfwN>

------
abalashov
Why not just use include?

------
alkavan
great news indeed. we are developing a dynamic (HMVC) CRM system using Kohana3
and PHP 5.2, traits can really help use do our CRUD system a lot more dynamic,
and probably other stuff too.

we are running the system on our own dedicated CentOS server ... and although
we are developing with PHP 5.3, the most updated _good_ package repository
I've found is Jason Litka's repo, with PHP 5.2.x, he says he still got
compatibly problems with the Zend Framework, so he won't update. so i guess
using 5.4 on production will take some time. and i'm not talking about other
virtual hosting providers who tend to update this things very slowly.

~~~
bystac
I'm using latest php5.3.3-fpm without any issues.

here corrected link to php53-fpm <http://dl.iuscommunity.org/pub/ius>

nginx latest repo <http://centos.alt.ru/pub/repository/centos/5>

