I use custom php attribute in my entity class,
and then there are service that read this attribute to prepare configuration array.
Something like this
class User implements UserInterface {
#[GridUi(label: 'ID')]
private int id;
#[GridUi(label: 'Email address')]
private string email;
#[GridUi(label: 'Full name')]
private string fullname;
}
But then I wonder, why not use static method like this
class User implements UserInterface {
private int id;
private string email;
private string fullname;
public static function getGridUiConfig()
{
return [
'columns' => [
['label' => 'ID', field: 'id'],
['label' => 'Email address', field: 'email'],
['label' => 'Full name', field: 'fullname'],
]
];
}
}
Now I use php attribute because this feels like best practice.
But in this case, what is the benefit using php attributes rather than static method?
In your example? There is no benefit. By all means, use a static method.
Remember, attributes are for metadata that describes something about a side-effect or behavior associated with the class/method/property. Not internal functionality.
For instance: Let's say you have a Controller class (common for routers and MVC paradigms). Let's also say that you want a particular piece of functionality to occur before or after a given route method within that class (ie: middleware).
Rather than defining your middleware internally on the class, or forcing your router to worry about the internals of each class that it's responsible for, you can use attributes that augment the behavior of your request/response lifecycle based on the presence of these attributes.
Basically, it's syntactic sugar to allow you to simply mark certain things that other areas of the application can respond to.
PHP 8 Attributes are a design pattern to add syntactic metadata.
Therefor there is no technical benefit, using them - afaik.
The actual benefits are,
Attributes
can be namespaced
can have zero or more parameters to it
may resolve to class names
Attribute class names can be imported with use statements
There can be more than one Attribute to a declaration
Sticking to your example, it is obviously way more readable than the static function.
Its benefits exceed the difference shown in your example.
Personally, I'd say the best features are the reusability and readability.
Related
With PHP 7 type declarations can be used to throw an exception if the provided parameter has another type than expected. Can this be used to only allow symfony entities?
/**
* #param User|MyOtherEntity $entity
*/
public function serialize(TYPEHINTFORENTITY $entity)
{
$json = json_decode($this->serializer->serialize(
$entity,
'json'
), true);
return $json;
}
public function deserialize($json, string $class): TYPEHINTFORENTITY
{
$entity = $this->serializer->deserialize(
json_encode($json),
'MyBundle\Entity\' . $class,
'json',
DeserializationContext::create()->setGroups(
array('group')
)
);
return $entity;
}
If I use the same function to serialize different entities I can't use
public function serialize(User $entity)
because that wouldn't allow entities of MyOtherEntity to be serialized.
Entities are not "special" objects from PHP point of view.
You can approach this in two ways
Define a common interface (probably without any methods), typehint it and let all the entities implements this
Use the object type for typehint that was introduced in PHP 7.2
With first solution you are safe if someone tries to pass something that's not an implementation of this interface. Of course you need to remember that every time a new entity is created in the codebase, it should implement that interface.
With second solution you're not safe as in the point one but you still be sure that everything that's passed is not a scalar or primitive type
With first solution you'll end up writing something like
interface Entity { }
class FooEntity implements Entity { }
class BarEntity implements Entity { }
...
public function serialize(Entity $entity) { }
With second solution just
public function serialize(object $entity) { }
First solution is recommended if you need to allow only those kind of entities whereas second is more permissive: both of them are just fine to me but you need to focus on what are the rules for your code
Edit
I've seen other answers suggesting to extend instead of implement an interface: please don't extend from a superclass if not strictly necessary as PHP classes can extend only from one class whereas them can implements multiple interfaces. Interface is the way to go if you need the first solution otherwise you'll be in trouble if you'll need some real extension imposed by the model
The best way to use type hinting on different types of object is to use a common Interface implemented by all entities which should be valid for your function.
For example in your case I would use
public function serialize(\Serializable $entity)
Imagine you have this class
class Ai1ec_Less_Parser_Controller {
/**
* #var Ai1ec_Read_Variables_Startegy
*/
private $read_variable_strategy;
/**
* #var Ai1ec_Save_Variables_Strategy
*/
private $write_variable_strategy;
/**
* #var Ai1ec_Less_Variables_Collection
*/
private $less_variables_collection;
/**
* #var Ai1ec_Less_Parser
*/
private $ai1ec_less_parser;
/**
* We set the private variables in the constructor. I feel that there are too many parameters.
* Should i use setter instead and throw an exception if something is not set?
*
* #param Ai1ec_Read_Variables_Startegy $read_variable_strategy
* #param Ai1ec_Save_Variables_Strategy $write_variable_strategy
* #param Ai1ec_Less_Variables_Collection $less_variables_collection
* #param Ai1ec_Less_Parser $ai1ec_less_parser
*/
public function __construct( Ai1ec_Read_Variables_Startegy $read_variable_strategy,
Ai1ec_Save_Variables_Strategy $write_variable_strategy,
Ai1ec_Less_Variables_Collection $less_variables_collection,
Ai1ec_Less_Parser $ai1ec_less_parser ) {
}
}
I need those variables to be set and so i set them in the constructor ( but that look like too many parameters ). Another option would be to use setters to set them and then in a method throw an exception if one of the required variables is not set like this
public function do_something_with_parser_and_read_strategy() {
if( $this->are_paser_and_read_strategy_set === false ) {
throw new Exception( "You must set them!" );
}
}
private function are_paser_and_read_strategy_set () {
return isset( $this->read_variable_strategy ) && isset( $this->ai1ec_less_parser );
}
Do you think that one of the two methods is better?And why?
Is your class immutable? If so, then having 100% member population via the constructor is often the best way to do it, but I'll agree it can start to look ugly if you have more than a 5 or 6 parameters.
If your class is mutable then there's no benefit from having a constructor with required parameters. Expose the members via accessor/mutator methods (aka properties).
The factory pattern (as suggested by #Ray) can help, but only if you have a variety of similar classes - for a one-off then you can simply use static methods to instantiate the object, but you'll still have the "too many parameters" problem.
The final alternative is to accept an object with fields (one field for each parameter), but use this technique carefully - if some values are optional then just use method overloading (which unfortunately PHP doesn't support).
I'd just stick with what you're doing and only change it for something else if it presents a problem.
Class naming Controller somehow reflects MVC, or in general - any mechanism responsible for processing sequence.
Data object classes tend to have many fields in any case - it is their responsibility.
Regular object relying on many other objects could be possibly missing a point.
There are four objects, as I see: read, save, parse and provide collection interface to something.
Why shall one have different interfaces for reading and writing? Could this not be combined into one?
Parser shall be a library on itself, thus there may be no reason to combine it anywhere, although it could possible use readers/writers for itself, and, in return, provide collection. Thus could it be possible that parser would take an argument of reader and return a collection object?
That is more about specific case.
In general - having many arguments to the method (or initializing many fields within an object by other objects of different domains) indicates some sort of design flaw.
Kind of on-topic might be this article on Constructor Initialization - it advises to use in-constructor initialization. Just be sure to follow up to the point:
What if there's a lot of collaborators to provide in the constructor? A large list of construction parameters, like any large
parameter list, is a CodeSmell.
And as Ray has written - there is a possibility to initialize using setters, and there is article on that too. To the extent of my view - I think that Martin Fowler really summarizes these cases pretty well.
There is no "better" way. But here are few things you have to consider:
constructors are not inherited
if class requires too many objects, it is responsible for too much
This might have impact on your choice of what sort of interface your class implements.
The general rule of thumb would be this:
If parameters are mandatory for class to function, they should be injected through constructor.
The exception would be, if you initialize the instance by using a factory. It is quite common for factory to build instance form diverse classes, where some of them implement same interface and/or extend same parent class. Then it is easier to inject shared objects through setters.
Creating your objects using factories that call setters instead of using a constuctor of a set number of parameters is much more flexible. Check out the builder and factory patterns.
Throwing exceptions for accessing not fully built objects is good!
Any function that has over 2 (sometimes 3) arguments, I always pass an array, so it would look like:
public function __construct(array $options = array()) {
// Figure out which ones you truly need
if ((!isset($options['arg1'])) || (mb_strlen($options['arg1']) < 1)) {
throw new Exception(sprintf('Invalid $options[arg1]: %s', serialize($options)));
}
// Optional would look like
$this->member2 = (isset($options['arg1'])) && ((int) $options['arg2'] > 0)) ? $options['arg2'] : null;
// Localize required params (already validated above)
$this->member1 = $options['arg1'];
}
Passing an array of options allows for future growth without having to change the function signature. However it does have it's drawback in that the function must localize all elements of the array to ensure access doesn't throw warnings / errors (if an element is missing from the array).
The factory solution is in this case is not a good choice, because you are still left with the problem of passing the values to the factory so it can initialize the object with the correct values.
The standard solution to "too many constructor arguments" is the builder pattern. Your controller class itself will still have a long constructor, but clients can use setters on the builder, which in turn will later call the long constructor.
If you only construct your controller object in one or two places, it wouldn't even be worth all the trouble to create a builder; in that case, just stick with your current code.
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 the 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__));
I've generally tried to stay away from PHP's magic methods because they seem to obfuscate an object's public interface. That said, they seem to be used more and more, at least, in the code I've read, so I have to ask: is there any consensus on when to use them? Are there any common patterns for using these three magic methods?
The main reason is that you do not need to type as much. You could use them for, say, an ORM record and act as implicit setters/getters:
using __call():
$user = new User();
$user->setName("Foo Bar");
$user->setAge(42);
$user->save();
using __set():
$user->name = "Foo Bar";
$user->age = 42;
which maps to a simple array:
array(
"name" => "Foo Bar",
"age" => 42
)
It is much easier to write such an array to the database than doing a lot of manual calls to collect all needed information. __set() and __get() have another advantage over public members: You are able to validate/format your data.
__call()
I've seen it used to implement behaviors, as in add extra functions to a class through a pluginable interface.
Pseudo-code like so:
$method = function($self) {};
$events->register('object.method', $method);
$entity->method(); // $method($this);
It also makes it easier to write mostly similar functions, such as in ORMs. e.g.:
$entity->setName('foo'); // set column name to 'foo'
__get()/__set()
I've mostly seen it used to wrap access to private variables.
ORMs are the best example that comes to mind:
$entity->name = 'foo'; // set column name to 'foo'
It allows you to do things like this:
class myclass {
private $propertybag;
public function __get($name) {
if(isset($this->propertybag[$name]) {return $this->propertybag[$name];}
throw new Exception("Unknown property " . (string) $name);
}
}
Then you can populate $propertybag from a SQL query in a single line, rather than setting a whole bunch of properties one by one.
Also, it allows you to have specific properties which are read-only (ie don't allow them to be modified via __set()). Maybe useful for an ID field, for example.
Also, you can put code into __get() and __set(), so you can do something more complex than just getting or setting a single variable. For example, if you have a storeID field, you may also want to provide a storeName property. You could implement that in __get() via a cross-reference lookup, so you may not need the name actually to be stored in the class. And of course storeName would not want to be implemented in __get().
Lots of possibilities there.
There are of course some down-sides of using magic methods. The biggest one for me is the fact that you lose the auto-complete functionality in your IDE. This may or may not matter to you.
Since magic methods can save you a LOT of coding when it comes to repetitive tasks like defining members, populating them and then retrieving them - instead of doing that boring, long piece of work, you can use mentioned 3 methods to shorten the time to code all that. If needed, I can provide a few examples tho they can be found in various tutorials over the net.
I don't know if it's general consensus, but the usual should apply - use where appropriate. If you find yourself to do repetitive task (define member, populate member, get member, call X functions that differ slightly) - magic methods might help you.
One common pattern is to have a single handle for your clients and proxy the calls to encapsulated objects or singletons based on naming conventions or configurations.
class db
{
static private $instance = null;
static public function getInstance()
{
if( self::$instance == NULL )
self::$instance = new db;
return self::$instance;
}
function fetch()
{
echo "I'm fetching\n";
}
}
class dataHandler
{
function __call($name, $argv)
{
if( substr($name, 0, 4) == 'data' )
{
$fn = substr($name, 4);
db::getInstance()->$fn($argv);
}
}
}
$dh = new dataHandler;
$dh->datafetch('foo', 'bar');
Same principles can be used to drive different backends of the same functionality without having to change the driver.
Whenever you'd like, as long as the magic properties/methods are documented; undocumented magic should be avoided unless working with a very abstract layer of code, such as when developing an ORM.
acceptable at an abstract layer
/**
* DB backed model base class.
*/
class Model {
protected $attributes = [];
function __get($name) {
return #$this->attributes[$name];
}
}
acceptable when documented
/**
* User model backed by DB tables.
* #property-read string $first_name
* #property-read string $last_name
*/
class UserModel extends Model {
}
lazy and unacceptable (and common when using ORMs)
/**
* This class is magical and awesome and I am a lazy shithead!
*/
class UserModel extends WhoCaresWhenEverythingIsMagical {
}
Can you explain what the reasoning would be on why I would want to use "protected" versus "public" or "private" on some class variables and methods in PHP5? I've just yet to find a case where I thought I needed "protected", and have either opted for "public" or "private" based on the intent. Even when working in teams, I have still yet to find a case (based on my knowledge thus far) of why "protected" is necessary for class variables and methods.
For instance, the Flourish library's fDate class provides a lot of functionality but not everything I need. So I extended w/ my own class.
I soon found out that its core internal variable, fDate::$date (time in seconds since 1970), was a private property. This made it impossible for me to access it in my subclass ThriveDate. Once the maintainer of Flourish changed it to a protected property, I was able to use it and thus adequately extend fDate.
Since you never know who might need to extend your class, and by how much, in the future, it's always best to make every internal property protected, unless there are great reasons for the property to never be modified by subclasses.
TL;DR: Private properties should be as rare as public properties: e.g. used almost never.
With protected its possible for an object of the class or any subclass to access that property. So its useful, if you want this restriction.
This is not strictly necessary, you can also make every property public, but then you will lose every control, who access and/or changes it. Also others may get confused, what all these "public properties" are good for, for which they have access to.
On the other hand you can make every property private, but then also every subclass can not access it anymore.
What about a real life example:
<?
// burguers.php
/* abstract */ class BurguerClass {
// nobody knows about these secret function
private function addSecretRecipeSauce() { ... }
// these one can can change in subclasses
// cannot be called globally
protected /* virtual */ function addBread() { ... }
protected /* virtual */ function addSalad() { ... }
protected /* virtual */ function addMeat() { ... }
protected /* virtual */ function addExtraIngredients() { ... }
// these one it can be access globally
public /* virtual */ function makeBurguer() {
$this->addBread();
$this->addSalad();
$this->addMeat();
$this->addExtraIngredients();
$this->addSecretRecipeSauce();
}
}
/* concrete */ class CheeseBurguerClass extends BurguerClass {
protected /* virtual */ function addCheese() { ... }
public /* override */ function makeBurguer() {
$this->addBread();
$this->addSalad();
$this->addMeat();
$this->addExtraIngredients();
// we add this one:
$this->addCheese();
}
}
/* concrete */ class RanchStyleBurguerClass extends BurguerClass {
protected /* override */ function addExtraIngredients() { ... }
}
/* concrete */ class EastCoastVegetarianStyleBurguerClass extends BurguerClass {
protected /* override */ function addMeat() {
// use soy "meat"
}
protected /* override */ function addExtraIngredients() { ... }
}
function burguers_main() {
$Cheesburguer = new CheeseBurguerClass();
// can be access
$Cheesburguer->makeBurguer();
}
// execute it
burguers_main();
?>
You just open the "Can I have a Cheesburguer" Software Development company. You are the C.E.O., you have several subordinates. You teach subordinates they can make new products based on the "burguerClass" recipe, and make new recipes.
You tell your employees how to "addBread" , "addSalad", "addMeat", "addExtraIngredients", and that operations can be changed by new ones, but cannot sell them separately, only can used in the "makeBurguer" operation.
But, you dont teach your employees the "addSecretRecipe" operation.
The way I understand it is that Private methods and properties cannot be seen by classes that extend; whereas Protected methods and properties can be seen but used only by the class it is defined within.
http://php.net/manual/en/language.oop5.visibility.php
when designing classes, isn't it normal to have private and public
variables or properties.
Granted my OOP experience is very limited, having
access to OOP development in CA-Visual Objects, Clipper, VB, and ASP.
But it was normal to have a series of public properties one could access
directly and then properties that could only be access by the class itself.
Of course in VB and ASP these were defined with Get, Let and Set methods,
but you could still access them directly.
You could also design properties that were read only as well.
Perhaps this is because of operator overloading...
I use protected methods and attributes rather than private mainly for testing purposes. This way it's much easier to create class mocks when writing unit tests.
OOP doesn't ends at organizing your code to classes (as structured programming doesn't ends at splitting code to functions). PHP is a script language, so when using it as OOP language, we should set up contstraints for ourselves.
I was very lucky, when I first met OOP, the language was Java, and the book was Bruce Ekcel - Thinking in Java (you can purchase it on Amazon or other stores, also previous editions can be downloaded from here for free: http://www.mindviewinc.com/Books/downloads.html ). I can recommend that book, even for PHP programmers. If you're not complete beginner, you will understand everything, and adopt it to PHP. I'm trying to programming in PHP like if it were Java (at least, the OOP part; there're no such cool associative arrays in Java, as in PHP).
Also, private, protected, and public categories are not too precise. Public should be split to "API method" and "can be called from other classes" (see "friendly"), protected should distinguish between "should be overwritten" and "must be implemented".
Learn OOP, it's worth.
There's one more thing I wanna to say, a basic pattern of OOP: use getters/setters, don't use public properties, if you use public properties, you just graved it to rock. Say, there's a status flag, now it has 2 possible state values, but if you wanna extend it, all the code must be revised, which use it. Use setState() and getState(), which functions first are simple ($this->state = $param; and return $this->state), but there will be no problem with extending the meaning of state, then you should re-write only these methods, even in the case, if the state is a derived value (e.g. its value is calculated from more flags).
There're several less or more deep similar topics in OOP, this getter/setter is probably the most important of the basic ones.
So, my tips are:
use OOP, it's your friend;
use PHP as like it were JAVA (a strict OOP language), and not like in FORTRAN.