Jump to content

Archived

This topic is now archived and is closed to further replies.

448191

Real world application of Traits

Recommended Posts

We're finally upgrading to PHP 5.4 coming release, and probably it's most prominent addition is that of traits (strictly mixins, but whatever).

 

Mxins in Ruby have always seemed a quick way to get you in a lot of shit, but 5.4 forces me to take another look at them, so I can formulate some guidelines for additions to our codebase. In other words, to make sure they are used without violating a truckload of design principles. Specifically SRP, or more generally cohesion look like a likely victim.

 

One possible application I see is reducing duplication, especially of boilerplate. In a way, a less complete solution to the problem solved by AOP, so the main Use Case I see is adding system/supporting features such as logging and access control. Example:

<?php

require 'vendor/autoload.php';

use Psr\Log\LoggerInterface;

trait UsesLogging
{
    private $logger;

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    public function getLogger()
    {
        return $this->logger;
    }

    protected function log($level, $message, $context = array())
    {
        $this->logger->log($level, $message, $context);
    }

}

use Psr\Log\LogLevel;

class SomeService
{
    use UsesLogging;
    
    public function doSomething()
    {
        $this->log(LogLevel::DEBUG, "I did something worth logging");
    }
}

How do you use traits?

Share this post


Link to post
Share on other sites

In hindsight not too happy about the naming of the trait, seems redundant prefix it with "Use". "use Logging" would a more appropriate statement.  Expressing a trait using a verb makes sense to me.

 

One caveat I run into is that using a trait does not affect type. I'm not completely convinced about the logic behind that decision.

 

The diamond problem is not applicable as mixins are conceptually different from inheritance, ensuring the sources for object composition are unequal and allowing precedence. Using a combination of traits that cause name collisions will not parse unless aliased.

 

In short, using a trait provides zero assurances for clients, meaning you have to define an interface as well, which seems somewhat redundant but unavoidable. The proposition "Traits are interfaces with implementation" is false, at least for the current PHP 5.4 implementation. Doesn't change it reduces duplication so it's still a win I guess. One has to ponder though, considering all the boilerplate involved, how useful traits are IRL.


use Psr\Log\LoggerInterface;

interface LoggingService
{
    public function setLogger(LoggerInterface $logger);
}

trait Logging
{
    private $logger;

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    protected function log($level, $message, $context = array())
    {
        $this->logger->log($level, $message, $context);
    }

}

use Psr\Log\LogLevel;

class SomeService implements LoggingService
{
    use Logging;

    public function doSomething()
    {
        $this->log(LogLevel::DEBUG, "I did something worth logging");
    }
}

$service = new SomeService;
$service->setLogger(new SomeLogger);
$service->doSomething();
var_dump($service instanceof Logging);

Share this post


Link to post
Share on other sites

How do you use traits?

I don't. Ive looked hard for a use case, and have even attempted to force myself to use them in some cases, but they have never felt right. There is always a better way, and IMO, I'd just avoid traits all together.

 

I really don't understand how things like traits get into the language yet things like property accessors don't.

 

os and ps: It's great to see you back around these parts John.

Share this post


Link to post
Share on other sites

I don't. Ive looked hard for a use case, and have even attempted to force myself to use them in some cases, but they have never felt right. There is always a better way, and IMO, I'd just avoid traits all together.

 

I

 

It looked smelly to me when evaluating Ruby, but might've been more useful if it worked as advertised: as interfaces with scope and implementation. I still view it as mostly a risk factor to implementation design, but it's there and I'm not one to forbid my developers using something unless I can properly motivate it. Right now it seems like a useful tool to reduce duplication, assuming you're very explicit about valid use (perhaps even reject pushes with abuse using the Git pre-receive hook). I have a more relaxed view on many things as the past couple of years I've shifted from producing good code to validating the quality of code.

 

 

os and ps: It's great to see you back around these parts John.

 

 

I

 

 

Thanks Tony :)  You've come a long way btw, Proem looks pretty good (although I'm not a big fan of event orientation in a synchronous environment). I might stick around, things are a bit more relaxed at work now compared to last 2 years which were extremely stressful (abnormal by any standard, I've been declared insane for my persistence by pretty much all my friends and family).

 

We'll see, I still have the same concerns about PHPFreaks that made me abandon it in the first place: the lack of advanced topics and competent sparring partners. That probably sounds insanely pompous but you probably get that. Right now I'm content sharing my experiences but that'll get boring at some point.

 

I'm rambling again :)

 

Share this post


Link to post
Share on other sites

I'm not sure I understand why they felt the needed to add traits, other than to appease people who really can't live without multiple inheritance. The syntax does seem a bit wonky. Still, I agree it looks like it can make things simpler and reduce the need for boilerplate code when using interdependent class libraries.

Share this post


Link to post
Share on other sites

Proem looks pretty good

Thanks man, but Proem has fallen over probably six months ago. The birth of my son was 8 months ago and I have since had a major priority shift.

 

I'm pretty happy just working my 9-5 at the moment, plenty enough challenges there so....

 

I still have the same concerns about PHPFreaks that made me abandon it in the first place: the lack of advanced topics and competent sparring partners.

I doubt that will every change. This community doesn't have the same focus as a community centered around some OSS project.

Share this post


Link to post
Share on other sites

the lack of advanced topics

We're a help forum and any decent programmer that would be able to provide an advanced topic is able to solve it himself and does not require any help, or knows how to find it without having to resort to a slow medium like a forum. So by definition we are a tutoring platform for newbie programmers. Even SO has this problem. Although their traffic is way above ours, the number of advanced topics that would pass there on a day is close to a few to none.

 

competent sparring partners

What would we be sparring about? The best solution to a question asked on the forum? The better explanation? The better "go-fuck-yourself" answer?

 

In a way, a less complete solution to the problem solved by AOP

I don't think AOP solves anything. It gives you the illusion of not having dependencies while they are simply lurking in the dark. If I need logging I simply add a LoggerAwareInterface and DI does the rest.

 

And if there is some cross-cutting concern with a dependency that could hinder re-use I can always use a Proxy (which is btw how the better AOP frameworks operate).

 

"No object lives in isolation" and you can have loosely-coupled objects but you can't have anything beyond that point besides the illusion you do.

Share this post


Link to post
Share on other sites

We're a help forum and any decent programmer that would be able to provide an advanced topic is able to solve it himself and does not require any help, or knows how to find it without having to resort to a slow medium like a forum.

I could not disagree more. You are implying that once you reach a certain level, you become so self-sufficient that all other views become irrelevant. That rushes by self-confidence straight into complete delusion. Not even the greats (Fowler, Evans, Uncle Bob) dare take that standpoint. And yes, a forum is a slow way of communicating, but also a way to communicate with people outside your reach in terms of physical contact. A forum will always be a great way to share your opinions, in fact, for plain "ask a question get a valid answer" type of communication, platforms like stackoverflow are clearly superior. 

 

So by definition we are a tutoring platform for newbie programmers. Even SO has this problem. Although their traffic is way above ours, the number of advanced topics that would pass there on a day is close to a few to none.

I'll take your word on the statistics, but as I tried to make clear above, in my view a forum should be more than Q&A, and to be brutally honest can never compete with SO focusing only on that basic level of interaction. And tutoring might have been a core value at some point, looking at the depressing amount of tutorials added since I last visited PHPF, I'd say right now it's mostly a poor substitute for SO.

 

What would we be sparring about? The best solution to a question asked on the forum? The better explanation? The better "go-fuck-yourself" answer?

The "best" solution to a problem. There are a million ways to approach a certain problem as soon as you move beyond language facilities, and you can't underestimate the value of other's opinions, as they are based on their own experiences.

 

I don't think AOP solves anything. It gives you the illusion of not having dependencies while they are simply lurking in the dark. If I need logging I simply add a LoggerAwareInterface and DI does the rest.

 

And if there is some cross-cutting concern with a dependency that could hinder re-use I can always use a Proxy (which is btw how the better AOP frameworks operate).

 

"No object lives in isolation" and you can have loosely-coupled objects but you can't have anything beyond that point besides the illusion you do.

This is a whole different can of beans, that apparently you feel very strongly about. Which I can relate to, for I too at times feel like a genius in a world of idiots (when clearly I'm not, but it's easy to confuse lack of context with superiority). What I've come to realize though is that we all grip to our golden hammers, and there are many solutions to the same problem. That does not mean that one approach to attacking a problem is not a solution, in fact a solution that seems less ideal from one perspective might be the ideal solution considering the context.

 

AOP *does* solve a problem, but I think I already made clear it is not the only solution, and certainly not always the best. One aspect (no pun intended) AOP does address that OOP (with or without DI) doesn't handle is violations of SoC/SRP because of concerns related to infrastructure. Logging is the de facto example, but there are plenty of other real-life applications such as messaging (AMQP or any other form) and authorization (with a complex Service Layer or Domain Model this can easily become a PITA). There are other ways to solve this, such as publish/subscribe, but any decoupling comes at a cost and the cost of a solution depends on the context.

 

Anyway, way off topic, but I felt that required a lot of nuance, if not for your sake then for every other person who read or will read that post.

Share this post


Link to post
Share on other sites

I doubt that will every change. This community doesn't have the same focus as a community centered around some OSS project.

I get your point. Maybe I *should* become involved in some project but then I'd have to be pretty enthusiastic about it, because I don't want to be that guy that tells everyone everything should be done differently (and I know I will cause I'm insanely opinionated ;)) and then leave because of RL pressure without confidence that they'll do at least as well without me. And if it's a small project that might prove to be an issue. But I can think of plenty of projects with developers more competent than I am so maybe I should join one of those. Yet somehow I always come back to PHPF, like a bird returning to its nest hoping to find a skyscraper :P

Share this post


Link to post
Share on other sites

Please excuse the necrophilia since this is my own thread...

 

I've been using PHP Traits (again, mixins, not traits but hey) for a while now and the only use case I've found for them is a "quick duplication hack". If you have duplication and you're too lazy or stressed to revise your object model using aggregation, this is the hack of the day. 

 

In fact, from a semantical perspective, Scala is the only language that I know of that gets this right. It gets more right, like getting rid of interfaces which is a technical concept. But that's beside the point, conclusion of this thread and answer to the question of when to use traits: when you're fucked and need to hack your way out of massive duplication.

Share this post


Link to post
Share on other sites

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.