I have a collection of PHP classes that can be instantiated traditionally using constructors. Now I want to add the ability to instantiate these objects using YAML configuration files.
Here's an example of a configuration file describing a web form:
title: Contact
fields:
message:
type: text
required: true
topic:
type: dropdown
options: ["HTML", "CSS", "PHP"]
This should result in a Form object with two corresponding Field objects. In other words, the configuration files sometimes describe objects that c开发者_如何学Goontain other objects.
I don't want simply a mapping from YAML key/value pairs to PHP properties because I want to allow shorthand syntax in the configuration files. For instance, I want to abbreviate some property names and also be able to type something like default: today
, where "today" is not interpreted as a string literal but rather transformed into the current timestamp.
Since many of the classes are subclasses, I'm looking for a solution that also lets me somehow "inherit" configuration logic from the superclass.
I want to avoid modifying the existing classes, but I am willing to do so if it allows for a simpler solution. On second thought, I don't really mind modifying the existing classes; I'm just interested in the best solution.
How do I best create objects from configuration files in this manner?
You could take the following approach:
Each of your model-classes to be populated from the configuration-file should implement an interface with, for example, a method fromArray($data)
.
On the top-level you know the type of Object (a Form) you want to create. This object is instanciated and the data from your config-file passed to the fromArray-method. The object then traverses the configuration-data and "knows" what to do with each of the entries.
For each element of the 'fields'-array it can then pass the data on to the child-objects which can themselves traverse and handle the configuration properly (including things like interpreting 'today' in a special way for any field that accepts a date).
Just split up the responsibility of creating object into special methods that know how to handle this kind of object.
The first thing I would do would be to see if this wheel had been already invented by someone- which might involve looking at some of the ORM suggestions offered here: Good PHP ORM Library?
Edit: Or possibly more usefully in this case taking a look at YAML Symfony: http://components.symfony-project.org/yaml/ - this also lets you embed PHP in your configuration file, which should get around the shorthand field names as well.
I won't go into the details of implementing things yourself beyond that because there's a lot of different ways you might choose to do that and not having implemented them myself I wouldn't want to set you wrong, but I will suggest that if you're using shorthand syntax like that you will want some way of marking out that it is shorthand syntax - coding for default: today
is much more likely to be error prone than default : %%today%%
or other more specialised markup.
I haven't written much PHP myself, but I could see something like this working if you rolled your own with the help of Symfony's YAML. You could use the PHP Reflection class to get all the properties of an object and sub-objects and then use the Symfony YAML code to map YAML to an array, then map the array to properties. In your code that maps the array to the properties of your PHP objects, you could look for your special things like "today" and make them do special things.
You may need a way to mark properties to react a certain way to different inputs. I don't know if its possible in PHP, but in .NET you can mark properties with an Attribute class to let properties know to do special stuff.
Write your configuration in PHP.
$ContactConfig=array(
$title='Contact',
$fields=array(
'message'=>array(
'type'=>'text',
'required'=>true
),
'topic'=>array(
'type'=>'dropdown',
'options'=>array('HTML','CSS','PHP')
)
)
);
Write a PHP code generator which essentially converts the YAML config to PHP code. When you do it this way, an opcode cache (APC, eAccelerator, XCache, etc.) will make the script more efficient at runtime, instead of PHP having to interpret the YAML file every time it is loaded.
精彩评论