📜 ⬆️ ⬇️

Independently overloaded properties

The standard mechanism for overloading properties through the __get and __set methods is not very convenient for practical use, but with it you can create a convenient dsl for working with properties. Immediately an example of use (hereinafter, the adaptive typing pattern is used, which is recommended to be familiarized with in advance):

class Title extends ProtoObject {<br> protected $_text= '' ;<br> function set_text( $val ){<br> return $ this ->aTitleString( $val );<br> }<br> function get_text( $val ){<br> if ( empty( $val ) ) return '[untitled]' ;<br> return $val;<br> }<br><br> function aTitleString( $val ){<br> aString( &$val );<br> if ( strlen( $val ) > 255 ) $val= substr( $val, 0, 252 ) . '...' ;<br> return $val;<br> }<br>}<br><br>$title= new Title;<br>$title->text= 123;<br>var_dump( $title->text ); // string(3) "123" <br>var_dump( $title->text( '' )->text() ); // string(10) "[untitled]" <br>echo $title;<br> // Title Object <br> // ( <br> // [_text:protected] => <br> // )


Architecture


The field name must begin with an underscore, and the accessors must have the appropriate prefixes. If you do not specify a property-specific getter and / or setter, then common get_ and set_ will be used. The accessory interface is simple: they convert the value passed to them. A new value is transferred to the setter and the result is stored in the field. The getter enters the saved value and the result is output to the outside. In fact, accessors act as pre- and post-filters.

The property can be treated not only as a field, but also as a polymorphic function. If it does not pass arguments, then it works as a getter, if you pass one parameter - as a setter that supports "chains". If you pass more parameters, wait for the trouble ;-) To intercept calls to unknown methods whose names do not match the names of the properties, you can overload the _call method, which by default simply throws an exception.
')
Little bun - converting an object to a string by default makes it dump using print_r. In general, the recommendation about __toString is such that this method should call the string that most fully reflects the internal state of the object.

Some more examples of properties


protected $_count= 0;<br> function set_count( $val ){<br> $ this ->_message= null ;<br> return anUnsignedInt( $val );<br> }
Stores some non-negative integer value. Values ​​like '-2' and 2.1 will be converted to 2. If you pass a boolean value or, for example, a string with letters, an exception will be raised. I propose to implement anipnster anUnsignedInt by myself.

protected $_message;<br> function set_message( $val ){<br> throw new Exception( 'message is autogenerated property' );<br> }<br> function get_message( $val ){<br> if ( empty( $val ) ) $val= $ this ->_message= $ this ->title . ': ' . $ this ->count;<br> return $val;<br> }
Lazy property. You cannot manually set the value, since it is a function of the values ​​of other fields. However, this property caches the computed value in itself, therefore, in the setters of the fields on which it depends, you should write a reset of the cache.

protected $_point;<br> function set_point( $val ){<br> return Point::anInstance( $val );<br> }<br> function get_point( $val ){<br> return clone $val;<br> }
Keeps an object with some interface. If a non-object is passed, it instantiates Point with the corresponding parameters passed to it. If the parameters are not correct - an exception. When reading a property, only a clone is returned, and the stored object remains intact and private. We'll leave the implementation of the Typkaster as homework ;-)

Well, for a snack - the class "typed variable":
class Vary extends ProtoObject {<br><br> protected $_type;<br> function set_type( $type ){<br> aString( &$type );<br> if ( !function_exists( $type ) ) throw new Exception( 'unknown type' );<br> if ( $ this ->type ):<br> $ this ->_type= $type;<br> $ this ->val= $ this ->val;<br> endif;<br> return $type;<br> }<br><br> protected $_val;<br> function set_val( $val ){<br> return $val= call_user_func( $ this ->type, $val );<br> }<br><br> function __construct( $type ){<br> $ this ->type= $type;<br> }<br><br> function __toString( ){<br> return aString( $ this ->val );<br> }<br>}<br><br>$count= new Vary( aString );<br>$count->val= '5cm per second' ;<br>echo $count->type; // aString <br>var_dump( $count->val ); // string(14) "5cm per second" <br>$count->type= aSoftNumber;<br>var_dump( $count->val ); // int(5) <br>echo $count; // 5 <br>echo $count->val( '' ); // 0 <br>var_dump( $count );<br> // object(Vary)#1 (2) { <br> // ["_type:protected"]=> <br> // string(11) "aSoftNumber" <br> // ["_val:protected"]=> <br> // int(0) <br> // }


Actually the hero of the occasion


class ProtoObject {<br><br> static $version= 8;<br> static $description= 'common object extension' ;<br> static $license= 'public domain' ;<br><br> function __toString( ){<br> return print_r( $ this , true );<br>}<br><br> function __set( $name, $value= null ){<br> $ this ->_aPropertyName( &$name );<br> $method= 'set' . $name;<br> if ( !method_exists( $ this , $method ) ) $method= 'set_' ;<br> $value= $ this ->{ $method }( $value );<br> $ this ->{ $name }= $value;<br> return $ this ;<br>}<br> function set_( $val ){<br> return $val;<br>}<br><br> function __get( $name ){<br> $ this ->_aPropertyName( &$name );<br> $method= 'get' . $name;<br> if ( !method_exists( $ this , $method ) ) $method= 'get_' ;<br> $value= $ this ->{ $name };<br> $value= $ this ->{ $method }( $value );<br> return $value;<br>}<br> function get_( $val ){<br> return $val;<br>}<br><br> function __call( $name, $args ){<br> try {<br> $ this ->_aPropertyName( &$name );<br> } catch ( Exception $e ){<br> return $ this ->_call( $name, $args );<br> }<br> switch ( count( $args ) ){<br> case 0: return $ this ->__get( $name );<br> case 1: return $ this ->__set( $name, $args[0] );<br> default : throw new Exception( 'wrong parameters count' );<br> }<br>}<br> function _call( $name, $args ){<br> throw new Exception( 'method not found' );<br>}<br><br> function _aPropertyName( $val ){<br> if ( $val[0] !== '_' ) $val= '_' . $val;<br> if ( !property_exists( $ this , $val ) ) throw new Exception( 'property not found' );<br> return $val;<br>}<br><br>}

Source: https://habr.com/ru/post/95233/


All Articles