Modifying static array in inherited PHP classes
I'm wondering if there is an easy or recommended way of modifying just a portion of an array defined as static when doing inheritance in php. I'm using a static array to set up definition parameters in an object model to create XML query data for a web service. This particular services uses a single datatype for various parameters that consists of two values (keys) for a 'Code' and a 'Description' relating to th开发者_开发问答e code.
My model allows me to specify both 'default' and an array of 'valid' values that my code can check against when creating the DOMElement
. Granted, this particular usage only consists of two values so it would not be incredibly difficult to just define specific classes similar to the CodeDescriptionType
to handle these, but I see where it could be valuable to create other similarly inherited classes for specific request types and some of the data structures are MUCH longer than just two key/value pairs. Here's a sample of what the code looks like:
class CodeDescriptionType extends Shipping_xmlAbstract {
public static $_elementDefs = array(
'Code' =>
array(
'type' => 'string',
'min' => 1,
'max' => 1
),
'Description' =>
array(
'type' => 'string',
'min' => 0,
'max' => 1
)
);
public function __construct($name,$elem=null) {
parent::__construct($name,null,$elem);
}
}
I added $name to this version of my xmlAbstract
so that when multiple data elements are using the same structure, I can just pass in the key-name for that structure to create the appropriate DOM Element in the XML based on the CodeDescriptionType
. What I would like to be able to do is to add 'default' => "value"
and 'valid' = array(1,2,3,4)
parameters under just the 'code' key. If all else fails, I can add an additional two parameters to this class to pass in those two but I'd be curious to know if there's a way to modify the contents of a static array when inheriting from a parent class. (array_merge
won't work in the static context)
First, you ask:
I'm wondering if there is an easy or recommended way of modifying just a portion of an array defined as static when doing inheritance in php.
I'm not quite sure whether you're looking for a very domain-specific answer for your exact use case or a general answer, but here is one way you might add those properties in some subclass:
class Sub extends CodeDescriptionType {
public function __construct( $name, $elem = null ) {
parent::__construct( $name, null, $elem );
self::$_elementDefs['Code']['default'] = 'value';
self::$_elementDefs['Code']['valid'] = array( 1, 2, 3, 4 );
}
}
$c = new Sub( 'test', 'elem' );
print_r( Sub::$_elementDefs );
You can access static properties of a superclass in PHP using the self
keyword; the operation itself can be performed by simply assigning new values using the appropriate PHP array access notation.
It's true that you cannot perform any operation other than an assignment when you declare static (or any member) variables, but you can certainly modify it any way you'd like after declaration.
Is this what you're looking for? This code will properly add default
and valid
keys to the static array defined in your parent class according to your description in the question.
You also ask:
I'd be curious to know if there's a way to modify the contents of a static array when inheriting from a parent class. (array_merge won't work in the static context)
class Super {
public static $array1 = array( 1, 2 );
}
class Sub extends Super {
public static $array2 = array( 3, 4 );
public function __construct() {
self::$array2 = array_merge( super::$array1, self::$array2 );
}
}
$s = new Sub;
print_r( Sub::$array2 );
This works just fine; the arrays are merged. Of course, the merge would only happen if you instantiated the class; you could also put it in a static method. However, since there is no such thing as a static constructor in PHP, performing the actual merge requires the member to be public (so you can perform the merge yourself, outside of the class) or putting the merge code into the constructor or a static method that you call manually.
More information/test code revealing things about static inheritance in PHP:
class Super {
public static $array1 = array( 1, 2 );
}
class Sub extends Super {
public static $array1 = array( 3, 4 );
public function __construct() {
print_r( self::$array1 );
print_r( parent::$array1 );
print_r( super::$array1 );
}
}
This will print exactly as expected: parent
and super
will both spit out the array defined in the superclass, while self
will spit out the array defined in the subclass.
I ran into another need to create a new set of definitions for my DOMDocument wrapper mentioned in this post. I still haven't found any built-ins to merge array elements but due to the nature of this particular application I don't really want to just write standard inherited properties either because that would kind of defeat the purpose of writing a wrapper around DOMDocument in the first place. (If I end up going that route, I'll just write something to translate PHP object properties to DOMDocument elements and attributes - which may yet happen if I can find a way to easily build the defs from the xsd automatically)
I forgot this thread existed but essentially ended up doing what the answers suggested now that I have a better handle on the scopes in PHP after working with it for a few years. The new definitions I'm creating have a number of inherited (extension) types in the xsd to start with. So defining definitions in the PHP to help build the eventual elements in the DOMDocument being wrapped at multiple levels in the models is required anyway.
In the abstract parent base class (the one that actually does the dirty-work of wrapping the DOMDocument and building the various sub DOMElement pieces-parts) I added the following function:
public static function cascadeDefs($layer) {
if(!class_exists($layer)) {
$layerNS = __NAMESPACE__ . '\\DataTypes\\' . $layer;
if(class_exists($layerNS))
$layer = $layerNS;
}
if(class_exists($layer))
foreach($layer::$_elementDefs as $k => $v)
if(!isset(static::$_elementDefs[$k]))
static::$_elementDefs[$k] = $v;
}
I considered having it back-trace to figure out what the calling class was rather than passing in the $layer variable, but found it more useful to pass the class name in, as it allows me to also 'import' definitions from a class outside the PHP inheritance structure.
So, for example, if I have a one definition for a 'customerPaymentProfileType' type which shares base element (customerPaymentProfileBaseType class) names with a couple of other variations of payment profiles. Then there is another type which has an additional parameter but is otherwise identical to the customerPaymentProfileType.
One of the things I do with these definitions is I assign the 'element name' that is to show up in the final xml output from the DOMElement created in any sub-branch of the final xml within the main constructor of the base abstract class. Most of the 'base' definitions in the XML amount to the equivalent of an abstract class in PHP, not being used directly to define an element type but instead only serving as an extension for other types. customerPaymentProfile, however, is used directly as an XML type in one definition. I also have an issue that when the Extended (Ex) type definition is used, the XML element name is different and normally I pass the name it at the first non-abstract level. So rather than inherit from the simple type, I can inherit from baseType (which extends the main wrapper and includes the core element definitions), add the one unique to the extended definition, define the [different] element name, then import the additional parameters in the basic version.
// technically extends customerPaymentProfileType but that is not an abstract and has different naming
class customerPaymentProfileExType extends customerPaymentProfileBaseType
{
//public static $_attrNames = array();
public static $_elementDefs = array(
'customerPaymentProfileId' => array(
'type' => 'string', // numeric string
'min' => 0
)
);
/**
* inherited child of the xmlAbstract::__construct to build a request XML data element
* @param null|array $elem
*/
public function __construct($elem=null) {
parent::__construct('paymentProfile',null,$elem);
self::cascadeDefs(get_parent_class(__CLASS__));
// add types from customerPaymentProfileType also
self::cascadeDefs('customerPaymentProfileType');
}
}
under normal circumstances, the inherited array elements can be imported in from the parent with just the call to:
self::cascadeDefs(get_parent_class(__CLASS__));
精彩评论