Primus2: Features (Configuration)

IMPORTANT

This code has been deprecated and moved to another project.  This particular code is an old version of the configuration trait.  The code and new version are now kept up at asherwunk/phabstractic (github).  Please see the current blog post.

I am proud to announce the addition of ‘features’ to the Primus Artificial Intelligence Framework: Falcraft Module

Features (Mixins)

I’ve done some research, and I haven’t really found this as a type of pattern.  However, I did find something close to what I’ve done on Wikipedia:

In object-oriented programming languages, a mixin is a class that contains a combination of methods from other classes. How such a combination is done depends on the language, but it is not by inheritance.[citation needed] If a combination contains all methods of combined classes, it is equivalent to multiple inheritance.

Mixins encourage code reuse and can be used to avoid the inheritance ambiguity that multiple inheritance can cause [1] (the “diamond problem“), or to work around lack of support for multiple inheritance in a language.

The thing about PHP and the mixin’s I’ve developed is that they are not necessarily a class, instead the idea is that they are a trait that offers a particular feature to another class.  So you define a feature, something the class can do, such as logging, or being able to hold configurations (see below) and then you can add it to a particular class.

For example, say you want some of your classes to be able to be configured and store configurations.  You could have a base class that includes that feature and then, in a single inheritance system like PHP, have all classes inherit from that class so that they can contain default behaviors.  The problem with this is that you end up implementing all the class ‘features’ on the base class creating bloat and unneeded complexity in the inheriting classes, particularly if only a subset of the classes inheriting need the feature.

This is where mixins can be handy.  So, following our configuration example, I can implement a configuration system in a  trait, and then any particular class that needs to be able to be configured in a standard fashion can use that trait, and implement the corresponding interface.  As well, when a sub-class uses the feature ‘again’ (it is used in the parent class as well) the scope of the configuration stays with the class.  Suddenly we have only the classes that need that feature actually using that feature, and on top of that if we so choose we can re-implement the configuration functionality in a  different way (keeping the same interface of course).

Configuration

As it will be, I have implemented a configuration ‘feature’.  This class depends on the ZendConfig module of the Zend Framework (version 2.0 as noted in the composer file).  This also depends on ZendStdlib and ZendJson, so they are included as well.  The idea is that a class that uses this feature will gain a protected property $conf that stores all the configuration information.  I have implemented this as a ZendConfig object.  This has offered me some very useful functionality, as ZendConfig has ReadersWriters, and Processors for many various standards (such as JSON, YAML, arrays, and ini files).  As well, because the class tests for the interfaces provided by Zend/Config, you can implement further readers, writers, and processors for your own purposes.  I am planning to implement a database reader and writer.

You use the class by including the trait in your class.  This gives you the following public methods: configure(), saveSettings(), getSettings(), and processSettings().  Below is the undocumented code for $object->configure():

This method accepts either a filename, array, or Zend/Config object as the first parameter, and an optional format argument.  If you pass a filename the method automatically detects the format of the file form its extension.  So, loading XML from testconfig.json won’t work.  If you pass the format (as the extension such as ‘ini’) argument, then the $configure parameter is interpreted as the string to be passed into a Zend/Config object.

NOTE: There is also a customization option where you can override the classes used to read the configuration information by setting the class property ::configReaders.  The format for this array is ‘extension’ => ‘fully qualified class name’.  This array is merged with the standard array, so all original classes are maintained as well.  This is done on a per-class basis and is not inherited.

If you pass an array, or a Zend/Config object, it constructs/copies the appropriate object into $object->conf.  In this particular implementation, $object->conf will always be a Zend/Config object.

The undocumented code for $object->saveSettings() reads as follows:

As you can see we supply the filename, optional writer object, and a file exclusive lock parameter (for the Config\Writer\WriterInterface toFile() method.  This defaults to true, just as it does in the interface definition).  If we supply a writer object that is compatible with Config\Writer\WriterInterface, we take our $this->con Config\Config object and save it using the supplied object.  Otherwise we take the extension of the file to be written automatically (this is the only way to determine the format to be written) and instantiate the correct Config\Writer instance.

NOTE: As in ::configure() you can override and add to the writers array by declaring an array property in the using class ::$configWriters.  This is optional.  The format is array( ‘extension’ => ‘writer object’ );

If we want a string representation we use a special filename: #string.(extension).  Otherwise, we take the file and write the information to it.  This file can be read in by the above ::configure() function, for instance, right after object instantiation.

The following methods provide some additional functionality:

These two methods simply let you use a Zend/Config/Processor compliant object (you have to instantiate it yourself) to process the configuration of the class, and ::getSettings() is a shortcut to retrieving the object’s settings as a string in the desired format (must be in the same format as a file extension, e.g. ini, array, json, etc.)

NOTE: If you are using the YAML extension, you are required to either use the YAML PECL extension, or a separate external library.  The library access object is passed in through the $context argument for both ::configure() and ::saveSettings().

View on GitHub

photo credit: Ironic Light Swith in Brighton University’s Usability Lab via photopin (license)

kadar

I'm just a wunk, trying to enjoy life. I am a cofounder of http//originalpursuitssoc.com/ and I like computers, code, creativity, and friends.

You may also like...

Leave a Reply

%d bloggers like this: