Skip to content

Instantly share code, notes, and snippets.

@mattparker
Last active December 28, 2015 14:29
Show Gist options
  • Save mattparker/7153561 to your computer and use it in GitHub Desktop.
Save mattparker/7153561 to your computer and use it in GitHub Desktop.
Traits

Replace globals

E.g.

trait ConfigProvider {
    
    private $_configProviderConfig;
    
    public function setConfigProvider($cfg) {
    }
    
    public function getConfigProviderValue($key) {
        // lazy load and setConfigProvider the default
    }
}

Then any class that needs to know about system-wide config settings can use the trait. But unit tests can setConfigProvider to test different config settings.

Patching Library code

So, for example, class Lplt_Form_Element_Text extends Zend_Form_Element_Text extends Zend_Form_Element. I need some extra/different/whatever behaviour in Zend_Form_Element, but don't want to actually patch library code.

trait MyCustomFormBehaviour {

    public function doTheThing () {
    }
}
class Lplt_Form_Element Text extends Zend_Form_Element_Text {
    use MyCustomFormElementBehaviour;
}
class Lplt_Form_Element_Select extends Zend_Form_Element_Select {
    use MyCustomFormElementBehaviour;
}

So I don't have to patch library code but can add behaviour to all subclasses of Zend_Form_Element, with only copying and pasting the use statement.

Composing a complicated (but essentially Single Responsibility) class from easier to manage components

In Lamplight, Group_Select is a class that constructs (rather complicated) SQL statements in an OOP kind of way:

$sel = new Group_Select();
$sel->bodysOfType("user")
    ->attended("work", "2011-01-01", "2012-01-01")
    ->withAttribute("gender", "male")
    ->arePublished();

or something: this will eventually generate a 8-table (say, sometimes many more) SQL statement.

One refactoring might be:

class Group_Select {

    public function attended($type) {
        $this->_attendance = new Attendance_Select();
        return $this->_attendance;
    }
    public function attribute() {
        $this->_attribute = new Attribute_Select();
        return $this->_attribute;
    }
    public function buildSQL () {
        // put $this->_attendance, $this->_attribute etc together
        // to make a nice SQL statement
    }
}


class Attendance_Select {
    public function type($type) {
        return $this;
    }
    public function dates($from, $to) {
        return $this;
    }
}


// and then...

$sel = new Group_Select();
$sel->attended()->type("work")->dates($date1, $date2);
$sel->attribute()->field("gender")->values("male");
$sql = $sel->buildSQL();

With traits it might be

trait Attendance_Select {
    // all the logic around attendance things
}

trait Attribute_Select {
    // all the logic around attributes
}

class Group_Select {
    use Attendance_Select, Attribute_Select;
    // small amount of general logic
}

Need to think about the pros and cons of these two, not sure which I prefer...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment