I need some classes to befriend other classes in my system. Lack of this feature made me publicize some methods which shouldn't be public. The consequences of that are that members of my team implement code in a bad and ugly way which causes a mess.
Is there a way to define a friendship in php 5.3?
(I am aware of http://bugs.php.net/bug.php?id=34044 You might want to vote there if there is no simple solution).
I was seeking the same functionality and was able to implement a solution. To use it, just derive from class Friendship and specify the classes that are friends of your derived class. You can find it here: http://rommelsantor.com/clog/2011/04/23/php-5-3-class-friendship-support
In short, no. The generally accepted approach is to either educate your team on how to develop against your libraries or redesign. The first solution can be done quite easily by building docs with phpdoc and setting the visibility in the docbloc comments with #visibility, and of course actually documenting the classes. The second I wouldn't be able to comment on without knowing a little more detail.
/**
* Some helper class for LibraryInterface
*
* ATTENTION!
* This class should not be used outside this package.
*
* #visibility package
* #package mypackage
*/
class Helper
{
public function doStuff()
{
/* does stuff */
}
}
/**
* Class for accessing some part of the library.
*
* #visibility public
* #package mypackage
*/
class LibraryInterface
{
public function doStuff()
{
$this->helper->doStuff();
}
}
I'm not sure what you mean by "befriend". You can use abstract classes, in which any new class can "implement" that class. Or you can have classes extend other classes and make the methods, variables, etc "protected" as opposed to public or private.
If your team implements any code "in a bad and ugly way", then you may have bigger problems.
Related
What I am currently trying to do is to test the constructor of a class in an unit test.
I am not sure whether the instance of this object is a "god object", I would say it's not, since it only aggregates several other components.
Either way, I am open to a better design.
So the rough class diagram looks like this
World is the suspected god class. Its dependencies, ServiceProvider, CommandRegistry, EventHub and Environment are injected via its constructor.
In its constructor, World does the following things:
store its dependencies in private fields
register a hook ($this, 'onCommandIssued') with the eventHub so that the world receives notifications about all commands being executed not through the world instance itself (world having also a method executeCommand)
tell the environment to adopt the world: $this->environment->adoptWorld($this). The environment's role is to adapt the world to some of the realities of the running environment, for instance a web environment has some specific services which are not available in a console application environment (e.g. the "session" service)
notify via the event hub that the construction of the world has finished: $this->eventHub->notify(new WorldConstructedEvent($this));
Maybe this looks like a heavy constructor, but it simply is what is defined as "constructing the world".
The World is basically the gateway to send commands (as Data Transfer Objects, via World::executeCommand()) to which different services can register hooks.
Now to the problems/questions:
I am trying to unit-test this constructor, but I have to add a bunch of #uses annotations, which makes it feel like anything else but an unit test. What is it then, a functional test? Unit-testing World is awkward, testing anything else is really trivial and I don't see this problem emerging in any other test, which makes me ask myself why that is and how to improve the design.
Is World a god object? All it does is to aggregate other components and forward calls to them.
How to properly unit-test the methods of World? If I use lots of stubs and I dependency-inject them, is it still unit-testing?
This is for a domain-driven designed (complex) application and I am open to suggestions which would make the design better (testable and decoupled).
Please let me know in the comments if you need any more details.
As I don't know where this discussion will lead to, I may refine my questions.
I finally got to unit-test the class by setting up proper expectations and mock the dependencies:
<?php
namespace Common\World;
use TestFramework\TestCase;
class WorldTest extends TestCase
{
/**
* #test
* #covers \Common\World\World::__construct
* #uses \Common\World\World::setEventHub
* #uses \Common\World\Event\Adopted
*/
public function construction()
{
/** #var \Common\World\Environment $environmentStub |\PHPUnit_Framework_MockObject_MockObject */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
/** #var \Common\World\EventHub|\PHPUnit_Framework_MockObject_MockObject $eventHubStub */
$eventHubStub = $this->getMock('Common\World\EventHub');
$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnCallback(function (World $world) use ($eventHubStub) {
$world->setEventHub($eventHubStub);
return true;
}));
$eventHubStub->expects($this->once())
->method('trigger')
->with($this->isInstanceOf('Common\World\Event\Adopted'));
$this->assertInstanceOf('Common\World\World', new World($environmentStub));
}
/**
* #test
* #covers \Common\World\World::__construct
* #expectedException \RuntimeException
* #expectedExceptionMessage the environment has rejected this world for incompatibility reasons
*/
public function construction_rejected()
{
/** #var \Common\World\Environment $environmentStub */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnValue(false));
new World($environmentStub);
}
}
I'm developing a quite complex logistics management system which will keep growing into several other ERP related modules. Therefore, I am trying to have as much of the SRP and Open/Close Principles in place for ease of extension and domain based management.
Therefore, I decided to use Laravel and the following pattern (not sure if this has a name or not):
I will use the PRODUCT object for my example.
An object/entity/domain has a Class
class ProductService {}
This class has a Service Provider which is included in the providers array and is also autoloaded:
ProductServiceServiceProvider
The service provider instantiate (makes) the ProductRepository which is an interface.
The interface currently has a MySQL (and some Eloquent) called EloquentProductRepository implementation(s) and a ProductRepositoryServiceProvider binds the implementation which is also loaded and in the providers array.
Now a product has many different attributes and relationships with other domains and because the other domains (or entities) need to be fully detached and again abiding with the above principle (SRP etc..) I decided to also have the same structure for them as i do for the product...I know some might think that this is too much but we need to have the system very extendable and to be honest I like to be organised and have a uniform pattern (it doesn't take that much more time and saves me a lot later).
My question is this. The ProductService which handles all the business logic of the Product and makes the "Product" what it is will have several dependencies injected on creation of it's instance through the constructor.
This is what it has at the moment:
namespace Ecommerce\Services\Product;
use Ecommerce\Repositories\Product\ProductRepository;
use Ecommerce\Services\ShopEntity\ShopEntityDescriptionService;
use Content\Services\Entity\EntitySeoService;
use Content\Services\Entity\EntitySlugService;
use Ecommerce\Services\Tax\TaxService;
use Ecommerce\Services\Product\ProductAttributeService;
use Ecommerce\Services\Product\ProductCustomAttributeService;
use Ecommerce\Services\Product\ProductVolumeDiscountService;
use Ecommerce\Services\Product\ProductWeightAttributeService;
use Ecommerce\Services\Product\ProductDimensionAttributeService;
/**
* Class ProductService
* #package Ecommerce\Services\Product
*/
class ProductService {
/**
* #var ProductRepository
*/
protected $productRepo;
/**
* #var ShopEntityDescriptionService
*/
protected $entityDescription;
/**
* #var EntitySeoService
*/
protected $entitySeo;
/**
* #var EntitySlugService
*/
protected $entitySlug;
/**
* #var TaxService
*/
protected $tax;
/**
* #var ProductAttributeService
*/
protected $attribute;
/**
* #var ProductCustomAttributeService
*/
protected $customAttribute;
/**
* #var ProductVolumeDiscountService
*/
protected $volumeDiscount;
/**
* #var ProductDimensionAttributeService
*/
protected $dimension;
/**
* #var ProductWeightAttributeService
*/
protected $weight;
/**
* #var int
*/
protected $entityType = 3;
public function __construct(ProductRepository $productRepo, ShopEntityDescriptionService $entityDescription, EntitySeoService $entitySeo, EntitySlugService $entitySlug, TaxService $tax, ProductAttributeService $attribute, ProductCustomAttributeService $customAttribute, ProductVolumeDiscountService $volumeDiscount, ProductDimensionAttributeService $dimension, ProductWeightAttributeService $weight)
{
$this->productRepo = $productRepo;
$this->entityDescription = $entityDescription;
$this->entitySeo = $entitySeo;
$this->entitySlug = $entitySlug;
$this->tax = $tax;
$this->attribute = $attribute;
$this->customAttribute = $customAttribute;
$this->volumeDiscount = $volumeDiscount;
$this->dimension = $dimension;
$this->weight = $weight;
}
`
Is it bad practice to have as much arguments passed to the constructor in PHP (please ignore the long names of the services as these might change when the ERP namespaces have been decided upon)?
As answered by Ben below, in this case it is not. My question was not related to OOP but more to performance etc.. The reason being is that this particular class ProductService is what web deves would do with a controller, i.e. they would probably (and against principles) add all DB relationships in one ProductController which handles repository services (db etc..) and attaches relationships and then it suddenly becomes your business logic.
In my application (and I see most applications this way), the web layer is just another layer. MVC takes care of the web layer and sometimes other Apis too but I will not have any logic except related to views and JS frameworks in my MVC. All of this is in my software.
In conclusion: I know that this is a very SOLID design, the dependencies are injected and they really are dependencies (i.e. a product must have tax and a product does have weight etc..) and they can easily be swapped with other classes thanks to the interfaces and ServiceProviders. Now thanks to the answers, I also know that it is Okay to inject so many dependencies in constructor.
I will eventually write an article about the design patterns which I use and why I use them in different scenarios so follow me if you're interested in such.
Thanks everyone
Generally, no, It's not a bad practice, in most cases. But in your case, as said in the comments by #zerkms, it looks like your class is depending on a lot of dependencies, and you should look into it, and think on how to minimize the dependencies, but if you're actually using them and they should be there, I don't see a problem at all.
However, you should be using a Dependency Injection Container (DIC).
An dependency injection container, is basically a tool which creates the class by the namespace you provide, and it creates the instance including all the dependencies. You can also share objects, so it won't create a new instance of it while creating the dependencies.
I suggest you to ue Auryn DIC
Usage:
$provider = new Provider();
$class = $provider->make("My\\App\MyClass");
What happens here is this:
namespace My\App;
use Dependencies\DependencyOne,
Dependencies\DependencyTwo,
Dependencies\DependencyThree;
class MyClass {
public function __construct(DependencyOne $one, Dependency $two, DependencyThree $three) {
// .....
}
}
Basically, the Provider#make(namespace) creates an instance of the given namespace, and creates the needed instances of it's consturctor's parameters and all parameter's constructors parameters and so on.
I am using a framework that allows adding new components to the framework's base class. Is there any way to document these new methods without changing the frameworks files so I can click through to the method in my IDE.
I highly recommend against trying to inject a subclass. If the framework instantiates the class you're extending directly, you'll need to find a way to get it to use your subclass instead.
NetBeans and PhpStorm (and probably many others) will combine elements from multiple definitions of the same class/interface. This allows you to add properties and methods to any existing class without modifying the original source.
/**
* Framework controller base class.
* Provides helpers via __call().
*/
class Framework_Controller { ... }
Now create a file in your code base that you never require containing the same class definition. Your IDE should still parse it and merge its elements with the class above:
if (false) { // Safety first!
/**
* ACME Co. controller base class.
*
* #method ACME_Model_User getUser Load user via authentication helper
*/
class Framework_Controller { /* nothing to add */ }
}
You can try using an interface and declaring the methods normally instead of with #method. That is what we did with Zend_View since it's already an interface. I haven't tried mixing class with interface to see if PhpStorm likes it.
It depends mainly on IDE you are using. I think you should extend base class and add there some new methods/properties with phpdoc comments. Of course changing framework's files is no solution as you already mentioned
You could extend the original class, redefine the function, with new doc, and call the parent function.
e.g.
class newClass extends originalClass
{
/**
* New PHPDoc
*/
function functionName($a)
{
return parent::functionName($a);
}
}
Try to use #see or inline #link directives.
I have a trait that must always be mixed in to a subclass of \PHPUnit_Framework_TestCase. PhpStorm doesn't know this. Is there anything I can do to get PhpStorm to autocomplete and "typecheck" things like assertNull inside the trait?
<?php
trait MyTestUtils
{
public function foo()
{
$this->assertNu // autocomplete?
}
}
The best I could come up with so far is putting the following in each method:
/** #var \PHPUnit_Framework_TestCase|MyTestUtils $this */
But this is repetitive and doesn't understand protected memebers. Is there a better option?
Besides using the php docblock to document $this, the only other way I'm aware of, which also, arguably makes your trait more "safe" anyway, is to define abstract methods on the trait itself, e.g.:
trait F {
/**
* #return string[]
*/
abstract public function Foo();
/**
* #return self
*/
abstract public function Bar();
}
abstract class Bar {
use F;
/**
* #return bool|string[]
*/
public function Baz () {
if ($this->Bar()) {
return $this->Foo();
}
return false;
}
}
UPDATE: Since PhpStorm 2016.1.2 (build 145.1616) autocompletion in traits works out-of-the-box. It is smart enough to figure out what classes use the trait, and then provide the autocompletion. Link to the issue: https://youtrack.jetbrains.com/issue/WI-16368
Previously replied with:
You can use:
#method \PHPUnit_Framework_TestCase assertTrue($condition, $message = '')
...in docblock of the trait itself, but the downside is that you'd need to put #method for each method that you'd like to have autocomplete for, which is not too bad if you're using a sane number of method calls in your trait. Or, "document" only those methods that you're using most often.
I would argue that this is not a valid use-case for a PHP trait. Your trait, as written is not guaranteed to only be used on classes that extend \PHPUnit_Framework_TestCase. This introduces very tightly coupled code. The best practice of Traits is for them to be very loosely coupled and only be aware of their own contents.
I would instead recommend that you either:
create a subclass of \PHPUnit_Framework_TestCase that your test cases that need this functionality can extend
create custom assertion classes. These can many times be used for doing groups of custom assertions.
Both techniques are detailed here: http://phpunit.de/manual/4.1/en/extending-phpunit.html
These are the two recommended best practices for where to place helper methods such as these.
Suppose I'm writing a blog app: My Posts Entity should have a createddate, modifieddate, name, and slug property (the slug would be generated when I call setName() for the Entity). I want to reuse this code, but I also want to reuse it on-demand. I may, for instance, have a Log Entity which wants to use createddate, but not modifieddate or slug functionality.
Class inheritance, whether via traits (mixins) or abstract classes, seems to be an insufficient, or at least improper, approach to reusing this functionality, as it doesn't pass the is-a test. After all, the Entity has-a createddate, but isn't a createddate itself.. so we should use Composition rather than Inheritance, right?. However, observer doesn't seem to work here, since while I want to use this functionality on-demand, Doctrine's use of annotation and object properties seem to make horizontal injection difficult (and expensive?) without use of Reflection.
To show some code and simplify the question a bit: can I at once inject the following definition and functionality into an Entity without breaking DRY or good OOP (proper use of composition / inheritance) practice?
/**
* #var DateTime $createddate
*
* #ORM\Column(type="datetime")
*/
private $createddate;
/**
* #ORM\PrePersist
*/
public function createddatePrePersist() {
$this->createddate = new \DateTime('now');
}
My personal opinion is that you're trying to find the nail for your hammer. You don't have to use composition, inheritance, traits, or any OOP pattern for every entity.
I tend to consider that the creationDate is an inherent property of my entity, and any entity that requires a creation date has this property. One may argue that's repeating myself, but in my opinion that makes the whole entity much easier to read.
Oh, and if I may, I wouldn't use an ORM-specific method, which is not part of my domain model, to initialise the creation date. This would be done in my constructor:
/**
* #var DateTime $createddate
*
* #ORM\Column(type="datetime")
*/
private $createddate;
public function __construct()
{
$this->createddate = new \DateTime();
// ... and other business rules that need to be enforced in the constructor
}