Please help me. I need a better understanding PHP OOP principles.
If I have a class property which is immutable for all of the class instances it should be defined as static?
If so, is there a way to be sure that static properties are defined in all classes of that type? As I read in PHP manual, static properties cannot be controller neither by the interface nor by abstract classes? Or am I wrong?
Simple example.
<?php
// Parent class
abstract class Employee
{
abstract public function getAlias();
}
// Child classes
class Manager extends Employee
{
public function getAlias()
{
return 'manager';
}
}
class Security extends Employee
{
public function getAlias()
{
return 'security';
}
}
Tell me, where an alias property should be placed?
I have to be sure that any Employee descendants that will be created in future will have that property defined. Is it OK to keep that kind of properties in dynamic methods? Or they should be placed in constants, static methods or static properties?
Actually the current version is quite ok (if considered with no context) because it makes for a cleaner code, since it closer matches principle of least astonishment. Technically, you could rewrite it as this (but that would actually make it worse code):
abstract class Employee {
public function getAlias() {
return $this->alias;
}
}
class Manager extends Employee {
protected $alias = 'mngr';
}
$user = new Manager;
echo $user->getAlias();
Live code: https://3v4l.org/sjVOT
The more important aspect is the purpose of this code. You mentioned, that you would want to use something like this for dealing with single-table inheritance, but here is the important part:
Your domain entities should not be aware of how your persistence layer works.
And pulling structural information from the domain layer for use in some query-builder is a terrible idea. I would recommend for you to instead looks at data mapper pattern (you probably should actually read the PoEAA book).
Your domain entities should not know any details about how (or even "if") they is being saved or restored.
Related
I have an abstract class like this
<?php
abstract class AbastractCreationCommand extends AbstactCommand {
protected $repository;
function handle($payload) {
$this->repository->create($payload);
}
}
class TagCreationCmd extends AbstractCreationCommand {
function __constructor() {
$this->repository = new TagRepository();
}
}
?>
Questions:
is there a way I could enforce the definition of the repository class in the subclasseses of the AbstractCreationCommand ?
Do I need to create a test for each subclass and call handle method or is another way to test all my code?
Answering number 1: You cannot enforce the creation of anything in subclasses from within your abstract class. At least not during instantiation. Everything in the subclass is optional.
However, your code in the abstract class could check whether or not the necessary objects have been defined when executing the part of the code that needs it, like this:
abstract class AbastractCreationCommand extends AbstactCommand {
protected $repository;
function handle($payload) {
if (!$this->repository instanceof TagRepository) {
throw new \InvalidArgumentException('Need a TagRepository');
}
$this->repository->create($payload);
}
}
However, is likely doing the complaining too late. And the reason may be because you are using inheritance instead of composition, or are inheriting the wrong things.
First of all, you are not doing dependency injection. Your subclass should not directly instantiate that TagRepository. This leads to problems testing your abstract class' code, as well as the subclass code, because you cannot provide a mock object instead. This severely limits the ability to test your code in isolation.
Also, the subclass cannot work without knowing very specifically how to inherit the abstract class beyond implementing any abstract functions. If both abstract and subclass come from you as the author, I would consider it to be ok to impose doing all things correctly on you. But if you expect other developers to inherit that abstract class (and your question sounds like this might be the background problem), then you shouldn't do this at all.
Abstract classes do provide some common functions to a set of subclasses through inheritance. But the same thing could be achieved if you put all the code into a non-abstract class and inject this class into independent ex-sub classes. They will call these common functions as public methods instead of private or protected, and the testing of the common code is also easier, because the methods are public.
Also note that you already have three levels of inheritance, which is nearing a uncomfortable level: AbstractCommand -> AbstractCreationCommand -> TagCreationCmd.
The problem is that everything you change in AbstractCommand has to be done with two levels of inheriting objects in mind. You cannot simply change a protected variable's name. You cannot simply add a protected (or public) variable without checking if any of the sub classes already has such a variable with the same name - unless you intend to share it.
The problems with maintaining code that is inherited is not with the classes at the end of the inheritance chain, but with these at the top. Just think about how many classes might be affected with different usage contexts: If you have AbstractCreationCommands, you will have AbstractDeletionCommands and AbstractChangeCommands and AbstractDoNothingCommands, and a plethora of concrete commands of all these kinds doing plenty of different stuff. Just imaging that on each level, you have four classes - this makes you having to maintain one base class, four inheriting classes, and four times four concrete classes - for a whopping 21 classes in total, all of them having to be tested, and likely none of them gaining any benefit from being an instanceof AbstractCommand.
Answering number 2: Yes, you have to test all subclasses - these are the ones that get instantiated and used. You should also test the abstract class' code in isolation. PHPUnit offers to instantiate an abstract class with the mock framework, so any abstract method would be mocked and could be configured. However, I always have a bad feeling when I use a mock as the real tested object because I am not really testing the pure code, but some combination of mock code and real code.
A possible way out is to create a test class that barely does anything beyond extending the abstract class, and work with this one.
1.Yes. I do the same when I need to force instantiation of some dependancies. And this way is support GRASP: Creator principle.
Another way to accomplish that with dependency injection, but this way broke Creator principle:
class TagCreationCmd extends AbstractCreationCommand {
function __constructor(TagRepositoryInterface $tagRepository) {
$this->repository = $tagRepository;
}
}
If follow 3 rules of TDD you should write test for each line of code. So the answer is yes.
Is there a way I could enforce the definition of the repository class in the subclasseses of the AbstractCreationCommand ?
I don't see the necessity tbh. If your AbstractCreationCommand needs a repo to work, add it as a constructor param. This doesn't enforce the repo to be injected because a subtype can override the constructor, but it should be abundantly clear that an AbstractCreationCommand subtype requires some sort of repo then, e.g.
abstract class AbstractCreationCommand extends AbstractCommand
{
private $repository;
public function __construct(Repository $repository)
{
$this->repository = $repository
}
protected function getRepository(): Repository
{
return $this->repository;
}
// …
You could also use a Template Method pattern to indicate that any subtype will utilize a repo by adding an abstract getter for the repo. The subtype will have to implement that method then. It's then up to the developer to decide on the implementation:
abstract class AbstractCreationCommand extends AbstractCommand
{
public function handle()
{
$this->getRepository()->create();
}
abstract function getRepository(): Repository;
// …
If you really must enforce it at creation level, you can set the abstract type's constructor to final protected and do any subtype creation in a static factory method, e.g.
abstract class AbstractCreationCommand extends AbstractCommand
{
private $repository;
final protected function __construct(Repository $repository)
{
$this->repository = $repository;
}
// …
This now prevents direct instantiation of any subtypes via new. Trying to new a subtype, will result in PHP Fatal error.
Instead the subtype must be created like this:
class TagCreationCommand extends AbstractCreationCommand
{
private $foo;
public static function create(Repository $repository, Foo $foo)
{
$command = new static ($repository);
$command->setFoo($foo);
return $command;
}
protected function setFoo(Foo $foo)
{
$this->foo = $foo;
}
// …
Then you'd call TagCreationCommand::create(new TagRepository, new Foo); to get a new instance. Since you cannot override the constructor and have to call the parent constructor from within the static create method, you effectively enforce a Repository now to be there. I added the Foo stuff only to illustrate how you'd use additional dependencies.
As you can hopefully see, this requires quite a lot of gymnastics compared to the much more lightweight previous two approaches that will basically result in the same outcome. After all, if there is no repo, the code will fail. And since you are using tests, this will get noticed. So why bother?
Do I need to create a test for each subclass and call handle method or is another way to test all my code?
If you are overriding the handle method, you should test that behavior in a concrete test class for that subtype.
If your subtypes do not override the handle method, you can create an AbstractCreationCommandTest and put a test for the handle method in there. However, if that is the case, I wonder why you need the AbstractCreationCommand to be abstract in the first place because then it sounds like you just need a CreationCommand.
Following Yan Burtovoy's suggestion, I would go even further and actually enforce a DI container
<?php
abstract class AbastractCreationCommand extends AbstactCommand {
protected $repository;
function __constructor(\DI\Container $container) {
$this->repository = $container->get('TagRepository');
}
function handle($payload) {
$this->repository->create($payload);
}
}
You should create tests for everything that is exposed to users of your library (that would be your application).
So, if you have a subclass that relies on handle() being called then you should write a test for that. Reason being that in 6 months someone might change the inheritance or overwrite the handle() method and change the initial expected behaviour.
While this question is about methods of solving this problem, I am particularly interested in good clean OO design and solutions that conform to current PHP best practices. Thanks in advance for taking a look.
I have the following interface:
<?php
interface Tool {
/**
* Return the unique name of the tool
*/
public function getName();
}
The majority of classes that implement this interface in my project looks like this:
<?php
class Drill implements Tool {
protected $toolName = 'drill';
public function getName() {
return $this->toolName;
}
}
And so the problem is I have dozens of classes that repeat this logic, duplicating the $toolName property and getName() logic, breaking the simple rule of 'Don't repeat yourself'
One solution I have considered is the following:
<?php
abstract class BaseTool implements Tool {
public function getName() {
return $this->toolName;
}
}
Then simply have tool classes extend the abstract BaseTool class:
<?php
class Drill extends BaseTool {
protected $toolName = 'drill';
}
However this now means that I lose the ability to force implementing classes to define the function getName() if they extend the BaseTool class, which can lead to incorrect implementations.
I also think that by having the BaseTool class return $this->toolName, it is making assumptions about the implementing classes and breaks encapsulation.
I have used a simple example to demonstrate the problem but hope you get what I'm trying to solve, and that this problem may also relate to more complex situations. Appreciate your thoughts.
If you're using PHP 5.4.0+, check out traits!
You could create a ToolInterfaceTrait that just contains the getters / setters for the variable $toolName
Your attempt looks good. Nothing more to say.
However this now means that I lose the ability to force implementing classes to define the function getName() if they extend the BaseTool class, which can lead to incorrect implementations.
You still force them, they need to inherit a class which implements them or implement them on their own.
If it is not feasible that all classes which should implement Tool extend from BaseTool, feel free to create more base classes which implement getName() or implement it directly, like you wish.
Btw, if you plan that all tools should extend BaseTool, then the interface isn't necessary at all, at least not for this use case. Interfaces are used for situations where not all classes which are expeted to implement it are inherited from the same base class.
How to avoid duplicating implemented getter function in PHP
Abstract classes are often used to group duplicated code. You're on the right path. As for your doubts about the choice...
However this now means that I lose the ability to force implementing classes to define the function getName() if they extend the BaseTool class, which can lead to incorrect implementations.
By extending the BaseTool class, a class inherits getName() (that's the idea with defining it in the abstract class). I'm not sure why that leads to incorrect implementations or why you'd have to "force implementing classes to define it." They get it automatically by extending the abstract class.
I also think that by having the BaseTool class return $this->toolName, it is making assumptions about the implementing classes and breaks encapsulation.
It might be cleaner if you define the toolName in the abstract class, and you set its value in the constructor?
<?php
abstract class BaseTool implements Tool {
protected $toolName;
public function __construct($toolName)
{
$this->toolName = $toolName;
}
public function getName() {
return $this->toolName;
}
}
You define a constructor in the extended class to put its name:
<?php
class Drill extends BaseTool {
public function __construct()
{
parent::__construct("drill");
}
}
I have an application with many classes in my Model, and each class has many properties.
Most of these classes share some properties, but in such a way that creating a class hierarchy using only single inheritance is not really suitable.
So I started creating some Traits containing only properties, without methods, such as:
trait Dateable {
protected $strat_date;
protected $end_date;
}
trait Featurable {
protected $image;
protected $description;
}
trait Buyable {
protected $price;
protected $buy_link;
}
etc... And then I define my classes like:
class Film {
use Featurable;
// some own properties...
}
class Showing {
use Dateable, Bookable;
// some own properties...
}
class Course {
use Featurable, Dateable, Bookable;
// some own properties...
}
This allows me to have a more organised model of classes, but I was wondering if this is a correct use of Traits because I can't find any examples of this...
Is not there any reason (e.g., performance) to avoid doing this?
It's incorrect in terms of OOP, because pure OOP suggests that you encapsulate everything possible. In general words, you should not have any public properties. All object's data should be accessible only by object's methods.
In your example, you have protected everywhere, but that is still a little bit incorrect, since it makes your code coupled on that trait meaning that you might get problems if you will try to disable it.
But if you will add getter-setter, then you are OK.
In fact, making those getters and setters abstract will ensure that your objects will be trully "Dateable, Featureable, Bookable, etc.".
A little bit better example would be trait called jsonParsable that has abstract function toJson(). Each class probably will have his own rules for returning JSON represenation, so it is good to make this trait abstract.
I'm working on a PHP project with a couple simple classes. I'm working on making my classes more complex, but I also wanted to start using classes for additional things like managing users, config settings, display, etc. I'm having a difficult time trying to figure out how to "organize" them. Like how should I extend these classes?
I have the following classes:
//main application settings, constants, etc.
Class Config {
}
//add/edit/delete/check permissions of users
Class Users extends Config {
}
//displays the pages
Class Display extends Config {
}
//main application
Class Analysis extends Config {
}
//specific methods for this type of analysis
Class Standard extends Analysis {
}
//specific methods for this type of analysis
Class Consolidated extends Analysis {
}
The issue I'm having is I want to be able to access the Users and Config classes from all the other classes (Display, Analysis, Standard, and Consolidated). How would I do this? Am I extending the classes properly? I feel like Display and Analysis should extend Users, but it doesn't seem right to me. I appreciate any help you can offer. Thanks!
In my projects my Users and Config classes are singleton classes which allows me to easily pull the instance into any other class with one simple method call.
Class User{
private static $_instance;
private function __construct(){
}
public function getInstance(){
if( !self::$_instance ){
self::$_instance = new User();
}
return self::$_instance;
}
}
Then wherever I need access to that user object
$user = User::getInstance();
You can try
trait Config {
}
// Common to Display
abstract class Display {
function __construct(Users $user);
}
// Common to analysis
abstract class Analysis {
function __construct(Users $user);
}
// add/edit/delete/check permissions of users
class Users {
use Config ;
}
// Mobile Display
class Mobile extends Display {
}
// Web Display
class Web extends Display {
}
// specific methods for this type of analysis
class Standard extends Analysis {
}
// specific methods for this type of analysis
class Consolidated extends Analysis {
}
// main application
class Main {
use Config ;
public function setDisplay(Display $display);
public function setAnalysis(Analysis $analysis);
}
$user = new Users("Jeff");
$main = new Main();
$main->setDisplay(new Mobile($user));
$main->setAnalysis(new Standard($user));
Keep them in separate files, and then use autoloading. Avoid the tendency to go OOP crazy. Remember that classes can be referenced as properties, not simply in an extension method.
As a general rule of thumb, you can use the "is-a" principle to organize your hierarchy of classes. For what you describe, it looks like:
Standard and Consolidated are (in the is-a sense) Analysis, so it looks like a good candidate for a hierarchy.
User and Display need to access the Config values, but they don't seem to be related in the conceptual way nor share common behavior, so it looks that composition is better suited than inheritance here.
Regarding the is-a principle you will generally recognize that it doesn't fit when the behavior that your subclass inherits doesn't belong to it. So, if for example your Config class has a saveValuesToDB() it definitely looks like something that the User shouldn't care about (i.e. how configuration values are stored in a DB). You can find a lot of information on the subject by searching for inheritance vs composition and is a recurrent subject in the pattern community. You can find a list of some good books about OO design and patterns here.
HTH
I am new to PHP and just get into OOP. I have few generic methods used to set and get properties. I use them quite often in almost all the classes, i put those methods in a class and extends other classes from it. Now i can access the methods from child class but dont know how set and get attributes of child class through them ... parent class base.php
class Base
{
public function __construct()
{
}
function __set($propName, $propValue)
{
$this->$propName = $propValue;
}
function setProperties(array $data)
{
foreach($data as $propName => $propValue)
$this->$propName = $propValue;
}
function __get($propName)
{
return (isset($this->$propName))? $this->$propName : "Invalid property!";
}
function getProperties(array $properties)
{
foreach($properties as $propName)
$propVals[$propName] = $this->$propName;
return $propVals;
}
}
child class categories.php
class categories extends Base
{
private $id;
private $pid;
private $title;
private $status;
public function __construct()
{
parent::__construct();
}
}
and i called it like
$objCat = new categories();
$objCat->setProperties(array('id'=>'10', 'pid'=>'6'));
print_r( $objCat->getProperties(array('id', 'pid')));
Need little guidance here. If its the right way? or at least is it possible to do it like this? if so how to accomplish this ...
thanks
Extending a class is something you only want to do when you can say class categories is a class Base. Something like that sort of utility class you have their is almost always the wrong way to go. PHP also has introduced something called traits for copy/paste code. However my personal preference is that it is something you will never want to use, because it tightly couples the traits to your class, which is something you want to avoid.
See for more information the Liskov Substitution principle in SOLID programming.
If it was up to me I would avoid those magic getters / setters either way and just add your own getters / setters methods to the class.
The mistake about some base class isn't something only you are doing (hell even I have done it in the past). Think about some class Database and a class Article. Because the Article class needs access to the database many people let the class extend the Database class. This isn't correct because an article isn't an database. Instead an instance of the database class should be injected into the article class by using dependency injection. The instance should either be injected into the class constructor (if all or many methods need access to it) or just the methods that need it. So when extending a class you have to be able to say class B is a class A.
Some other notes about your code:
Always make your class names PascalCase. This is not really required to make your code work, but it follows a naming convention often used.
And my personal preference a bit: please always add curly braces to your foreach statements. It is more clear what is happening when other people are reading your code.