I have classes MonthTimeCard and MonthReport. They use same input field for choosing month, so the validation is the same and initialisation is the same.
class MonthTimeCard {
private function setPrivateVarsByUserInput()
{
$this->month_from_input = '2015-09';
$this->date_from = '2015-09-01';
$this->date_to = '2015-09-30';
// lets say those 3 values are formated, validated and returned as array from MonthUserInput class.
// but I have to repeat code in my both classes to initialize them
// I could have one liner like $this->data = $this->monthUserInput->getInput();
// but current class code will need to call $this->data->[variable] everywhere - not looking very nice,
// because ->data is not usefull here, just extra characters.
}
}
Class MonthReport {
... same initialisation
}
I now just hard coded them but you know assignment will be from return array of MonthUserInput class which will validate. There is only one user input field which gets string like '2015-09' and MonthUserInput class will add first day and last day of month.
I could avoid this if I would use inheritance but I have read that should avoid and some even say that it should be removed from OOP.
http://blogs.perl.org/users/sid_burn/2014/03/inheritance-is-bad-code-reuse-part-1.html
With inheritance I would simply in do validating and setting user input in parent class and so no duplication.
How should I do this now? Of course its just 3 variables in this example, I plan to have 5, its not much, but still its duplication and with inheritance there would not be duplication in this case.
Update
I would like to see explanation which I could use to explain to anybody who do not agree that inheritance would be bad to this situation. For example I discussed with one experienced programmer and he does not see a problem here to use inheritance for code reuse. I just said there is lot on internet telling that use composition, but that was not good argument for this situation.
For example:
Favor composition over inheritance. If two classes don't have an "is
a" relationship, then it should never be necessary to use inheritance
to achieve code reuse. Never.
this would not be a good argument for some people. They can ask - who invented those rules and why? They do not see a problem by breaking this rule.
Inheritance is a powerful tool and can achieve code reuse, however it brings potential problems of its own and should be used appropriately. Because subclasses depend on the superclass implementation, inheritance breaks encapsulation and can make code more fragile and difficult to maintain.
Achieve the discipline to use inheritance only when there really is a "IS A" relationship, eg. a PreferredClient IS A Client ... or ... a MountainBike IS A Bike. If you are designing a class that doesn't achieve an IS A relationship with an intended superclass, then don't use inheritance.
You can achieve a similar degree of code reuse by using composition instead of inheritance. Instead of making a subclass, incorporate the intended superclass as an attribute of your class. This allows you to delegate method calls to the contained instance and achieve code reuse.
For your code example, a suggested code decomposition might be this:
class MonthTimeCard {
Month myMonth;
MonthTimeCard(Month month) { myMonth = month; }
private function setPrivateVarsByUserInput() {
// calls to myMonth
}
}
Class MonthReport {
// calls to myMonth
}
Class Month {
$this->month_from_input = ...
$this->date_from = ...
$this->date_to = ...
}
If MonthTimeCard and MonthReport do not logically extend each other (such as Dog and Cat are sub types of Animal), its not a good idea to use inheritance here anyway.
Besides that, if you do the same validation at multiple locations, you could introduce a standalone DateValidator class and use that whenever required.
public class DateValidator {
public static boolean validate(final String dateString) {
return ...; // TODO: Validate user input here
}
}
Related
Sorry if this is a duplicate question or a common design principle, I have searched around but was unable to find any answers to this question. I'm probably just searching with the wrong keywords.
I have been looking at a popular library Sabre/Event (https://sabre.io/event/) and in the code there is a simple class/inheritance model that I am trying to understand:
The class EventEmitter implements EventEmitterInterface and uses EventEmitterTrait (see below for code).
There is a comment in EventEmitterTrait above the class which says:
* Using the trait + interface allows you to add EventEmitter capabilities
* without having to change your base-class.
I am trying to understand why this comment says this, and why it allows adding capabilities without changing the base class, and how that is different from just putting the routines into EventEmitter itself.
Couldn't you just extend EventEmitter and add capabilities in the derived class?
Simplified code:
// EventEmitter.php
class EventEmitter implements EventEmitterInterface {
use EventEmitterTrait;
}
// EventEmitterInterface.php
interface EventEmitterInterface {
// ... declares several function prototypes
}
// EventEmitterTrait.php
trait EventEmitterTrait {
// ... implements the routines declared in EventEmitterInterface
}
You're basically asking two questions here.
What are interfaces and why are they useful?
What are traits and why are they useful?
To understand why interfaces are useful you have to know a little about inheritance and OOP in general. If you've ever heard the term spaghetti code before (it's when you tend to write imperative code that's so tangled together you can hardly make sense of it) then you should liken that to the term lasagna code for OOP (that's when you extend a class to so many layers that it becomes difficult to understand which layer is doing what).
1. Interfaces
Interfaces diffuse some of this confusion by allow a class to implement a common set of methods without having to restrict the hierarchy of that class. we do not derive interfaces from a base class. We merely implement them into a given class.
A very clear and obvious example of that in PHP is DateTimeInterface. It provides a common set of methods which both DateTime and DateTimeImmutable will implement. It does not, however, tell those classes what the implementation is. A class is an implementation. An interface is just methods of a class sans implementation. However, since both things implement the same interface it's easy to test any class that implements that interface, since you know they will always have the same methods. So I know that both DateTime and DateTimeImmutable will implement the method format, which will accept a String as input and return a String, regardless of which class is implementing it. I could even write my own implementation of DateTime that implements DateTimeInterface and it is guaranteed to have that method with that same signature.
So imagine I wrote a method that accepts a DateTime object, and the method expects to run the format method on that object. If it doesn't care which class, specifically, is given to it, then that method could simply typehint its prototype as DateTimeInterface instead. Now anyone is free to implement DateTimeInterface in their own class, without having to extend from some base class, and provide my method with an object that's guaranteed to work the same way.
So in relation to your EventEmitter example, you can add the same capabilities of a class (like DateTime) to any class that might not even extend from DateTime, but as long as we know it implements the same interface, we know for sure it has the same methods with the same signatures. This would mean the same thing for EventEmitter.
2. Traits
Traits, unlike interfaces, actually can provide an implementation. They are also a form of horizontal inheritance, unlike the vertical inheritance of extending classes. Because two completely different class that do not derive from the same base class can use the same Trait. This is possible, because in PHP traits are basically just compiler-assisted copy and paste. Imagine, you literally copied the code inside of a trait and just pasted it into each class that uses it right before compile time. You'd get the same result. You're just injecting code into unrelated classes.
This is useful, because sometimes you have a method or set of methods that prove reusable in two distinct classes even though the rest of those classes have nothing else in common.
For example, imagine you are writing a CMS, where there is a Document class and a User class. Neither of these two classes are related in any meaningful way. They do very different things and it makes no sense for one of them to extend the other. However, they both share a particular behavior in common: flag() method that indicates the object has been flagged by a user for purposes of violating the Terms of Service.
trait FlagContent {
public function flag(Int $userId, String $reason): bool {
$this->flagged = true;
$this->byUserId = $userId;
$this->flagReason = $reason;
return $this->updateDatabase();
}
}
Now consider that perhaps your CMS has other content that's subject to being flagged, like a Image class, or a Video class, or even a Comment class. These classes are all typically unrelated. It probably wouldn't make much sense just to have a specific class for flagging content, especially if the properties of the relevant objects have to be passed around to this class to update the database, for example. It also doesn't make sense for them to derive from a base class (they're all completely unrelated to each other). It also doesn't make sense to rewrite this same code in every class, since it would easier to change it in one place instead of many.
So what seems to be most sensible here is to use a Trait.
So again, in relation to your EventEmitter example, they're giving you some traits you can reuse in your implementing class to basically make it easier to reuse the code without having to extend from a base class (horizontal inheritance).
Per Sabre's Event Emitter's docs on "Integration into other objects":
To add Emitter capabilities to any class, you can simply extend it.
If you cannot extend, because the class is already part of an existing
class hierarchy you can use the supplied trait.
So in this case, the idea is if you're using your own objects that already are part of a class hierarchy, you may simply implement the interface + use the trait, instead of extending the Emitter class (which you won't be able to).
The Integration into other objects documentation says:
If you cannot extend, because the class is already part of an existing class hierarchy you can use the supplied trait".
I understand it's a workaround when you already have an OOP design you don't want to alter and you want to add event capabilities. For example:
Model -> AppModel -> Customer
PHP doesn't have multiple inheritance so Customer can extend AppModel or Emitter but not both. If you implement the interface in Customer the code is not reusable elsewhere; if you implement in e.g. AppModel it's available everywhere, which might not be desirable.
With traits, you can write custom event code and cherry-pick where you reuse it.
This is an interesting question and I will try to give my take on it. As you asked,
What is the purpose of using traits to define functions for an interface ?
Traits basically gives you the ability to create some reusable code or functionality which can then be used any where in your code base. Now as it stands, PHP doesn't support multiple inheritance therefore traits and interfaces are there to solve that issue. The question here is why traits though ?? Well imagine a scenario like below,
class User
{
public function hasRatings()
{
// some how we want users to have ratings
}
public function hasBeenFavorited()
{
// other users can follow
}
public function name(){}
public function friends(){}
// and a few other methods
}
Now lets say that we have a post class which has the same logic as user and that can be achieved by having hasRatings() and hasBeenFavorited() methods. Now, one way would be to simply inherit from User Class.
class Post extends User
{
// Now we have access to the mentioned methods but we have inherited
// methods and properties which is not really needed here
}
Therefore, to solve this issue we can use traits.
trait UserActions
{
public function hasRatings()
{
// some how we want users to have ratings
}
public function hasBeenFavorited()
{
// other users can follow
}
}
Having that bit of logic we can now just use it any where in the code where ever it is required.
class User
{
use UserActions;
}
class Post
{
use UserActions;
}
Now lets say we have a report class where we want to generate certain report on the basis of user actions.
class Report
{
protected $user;
public function __construct(User $user)
{
$this->user = $user
}
public function generate()
{
return $this->user->hasRatings();
}
}
Now, what happens if i want to generate report for Post. The only way to achieve that would be to new up another report class i.e. maybe PostReport.. Can you see where I am getting at. Surely there could be another way, where i dont have to repeat myself. Thats where, interfaces or contracts come to place. Keeping that in mind, lets redefine our reports class and make it to accept a contract rather than concrete class which will always ensure that we have access to UserActions.
interface UserActionable
{
public function hasRatings();
public function hasBeenFavorited();
}
class Report
{
protected $actionable;
public function __construct(UserActionable $actionable)
{
$this->actionable = $actionable;
}
public function generate()
{
return $this->actionable->hasRatings();
}
}
//lets make our post and user implement the contract so we can pass them
// to report
class User implements UserActionable
{
uses UserActions;
}
class Post implements UserActionable
{
uses UserActions;
}
// Great now we can switch between user and post during run time to generate
// reports without changing the code base
$userReport = (new Report(new User))->generate();
$postReport = (new Report(new Post))->generate();
So in nutshell, interfaces and traits helps us to achieve design based on SOLID principles, much decoupled code and better composition. Hope that helps
I'm trying to design some class hierarchy and I got "stuck" at this part.
Lets say that I have following classes
abstract class Video
{
const TYPE_MOVIE = 1;
const TYPE_SHOW = 2;
abstract public function getTitle();
abstract public function getType();
}
class Movie extends Video
{
// ...
public function getType()
{
return self::TYPE_MOVIE;
}
}
class Show extends Video
{
// ...
public function getType()
{
return self::TYPE_SHOW;
}
}
In the diffrent part of the system I have (Parser) class that encapsulates creation of
movie and show objects and returns obj. to the client.
Question: What is the best way to get a type of a obj. returned from parser/factory class, so that client can do something like
$video = $parser->getVideo('Dumb and Dumber');
echo $video->getTitle();
// Way 1
if($video->getType == 'show') {
echo $video->getNbOfSeasons();
}
// Way 2
if($video instanceof Show) {
echo $video->getNbOfSeasons();
}
// Current way
if($video->getType == Video::TYPE_SHOW) {
echo $video->getNbOfSeasons();
}
Is there a better way than my solution (read as: does my solution suck?)?
Is there a better way than my solution (read as: does my solution suck?)?
Your solution does not suck, per se. However, whenever someone is trying to determine the subtype to perform some actions, I tend to wonder; why? This answer might be a little theoretical and perhaps even a little pedantic, but here goes.
You shouldn't care. The relationship between a parent and a child class is that the child class overwrites the behaviour of the parent. A parent class should always be substitutable by it's children, regardless which one. If you find yourself asking: how do I determine the subtype, you're usually doing one of two things "wrong":
You're attempting to perform an action based upon subtype. Normally, one would opt for moving that action to the class itself, instead of "outside" of the class. This makes for more manageable code as well.
You're attempting to fix a problem you've introduced yourself by using inheritance, where inheritance isn't warranted. If there is a parent, and there are children, each of which are to be used differently, each of which have different methods, just stop using inheritance. They're not the same type. A film is not the same a tv-serie, not even close. Sure, you can see both on your television, but the resemblance stops there.
If you're running into issue number 2, you're probably using inheritance not because it makes sense, but simply to reduce code duplication. That, in and on itself, is a good thing, but the way you're attempting to do so might not be optimal. If you can, you could use composition instead, although I have my doubts where the duplicated behaviour would be, apart from some arbitrary getters and setters.
That said, if your code works, and you're happy with it: go for it. This answer is correct in how to approach OO, but I don't know anything about the rest of your application, so the answer is generic.
I'd go with way 2. It abstracts you the need to add another constant at Video in case you may want to add class SoapOpera extends Show (for instance).
With way #2, you are less dependent on constants. Whatever information you can gain without hardcoding it, means less problems to likely happen in the future in case you want to extend. Read about Tight an Loose Coupling.
I think the second option is better, using instanceof. This is in general common to all OOP design and not just PHP.
With your first option, you have specifics about derived classes in the base class, and thus must modify the base class for each new derived class you add, which should always be avoided.
Leaving the base class as-is when adding new derived classes promotes code reuse.
If there is a "right" way, and everything is subjective in coding of course (as long as it doesn't adversely impact performance/maintainability ;) ), then it's the second way as "Truth" and "Brady" have pointed out.
The upside of doing things the way you're doing them now (class constants in the abstract) is that when you're working with other developers it can provide hints as to how you expect the abstract class to be interacted with.
For instance:
$oKillerSharkFilm = Video::factory(Video::MOVIE, 'Jaws', 'Dundundundundundun');
$oKillerSharkDocumentary = Video::factory(Video::DOCUMENTARY, 'Jaws', 'A Discovery Shark Week Special');
Of course, the downside is that you have to maintain the "allowable extensions" in the abstract class.
You could still use the instanceof method as demonstrated in your question and maintain the list of allowable extension in the abstract predominantly for control/type fixing.
Had a discussion with a colleague about wether this is bad practice or not. Now I can not find immediate examples of this online.
We have a lot of database object mappers and call it's functions like so
(example) - the setId method get's the row from the database and set's it to predefined propertys
class Person {
public static function get($id) {
$object = new Person;
$object->setId($id);
return $object;
}
}
Using it like this we can use simple constructions like this: (where we got the id from for-example a post)
$person = Person::get($id);
instead of
$person = new Person;
$person->setId($id);
Now, my instinct tells me this is bad practice. But I can not explain it. Maybe someone here can explain why this is, or is not bad practice
Here are some other examples how we use it. we mainly use it for getters. (just the names, not the code. Almost all of them just run a query, which can return 1 object and then use the id of the result to use the setId method)
class CatalogArticle {
public static function get($id) { }
public static function getByArticlenumber($articlenumber) {} //$articlenumber is unique in the database
public static function getRandom() {} //Runs a query returning a random row
}
This isn't horrible persay. It's an implementation of a Factory Method design pattern. It's not bad at all in principle.
However, in your specific example, it's not really doing anything significant, so I'm not so sure if it's necessary. You could eliminate the need by taking a (perhaps optional) parameter to the constructor for the id. Then anyone could call $foo = new Person($id); rather than needing an explicit factory.
But if the instantiation is complex, or you want the ability to build several different people types that can only be determined by logic, a factory method may work better. For example, let's say you need to determine the type of person to instantiate by some parameter. Then, a factory method on Person would be appropriate. The method would determine what "type" to load, and then instantiate that class.
Statics in general are hard to test and don't allow for polymorphic changes like an instance would. They also create hard dependencies between classes in the code. They are not horrible, but you should really think about it if you want to use one. An option would be to use a Builder or a Abstract Factory. That way, you create an instance of the builder/factory, and then let that instance determine how to instantiate the resulting class...
One other note. I would rename that method from Person::get() to something a little more semantically appropriate. Perhaps Person::getInstance() or something else appropriate.
This blog post should tell you why people don't like static methods better than i could:
http://kore-nordmann.de/blog/0103_static_considered_harmful.html
The question that strikes me most about your current code snippet: Is a Person allowed to NOT have an Id ?
I feel like that should be an constructor argument if it's representing a real Person. If you use that class to create new persons that ofc might not work.
The difference between the 2 calls is minor. Both "create" a Person class and set the Id so you are not winning / loosing anything there when it comes to 'hard wired dependencies'.
The advantage only shows when you want to be able to pass a Person into another object and that objects needs to change the ID (as an example, the blog post should explain that better than i did here).
I'm only adding to edorian's post, but I've used static get methods in the past, where there is a caching engine in place, and (for example) I might have a given Person object in memcache, and would rather retrieve it from the cache than going off to the database.
For example:
class Person {
public static function get($id) {
if(Cache::contains("Person", $id))
{
return Cache::get("Person", $id);
}
else
{
//fictional get_person_from_database, basically
//getting an instance of Person from a database
$object = get_person_from_database($id);
}
return $object;
}
}
In this way, all cache handling is done by the class in question, rather than the caller getting a person calls having to worry about the cache.
long story short, yes, they are bad practice:
http://r.je/static-methods-bad-practice.html
http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/
A good reason apart of everything is that you 'should' be testing your code. Static methods cause issues, so there you have a good reason:
if you want to follow good practices, test your code
Ergo, if static causes testing issues, static prevent writing tests so it prevents to follow good practices :-)
time goes things changes.
just in case you have problems with testing you can use AspectMock library
https://github.com/Codeception/AspectMock
any way static is not so bad at all. to use static you should just know what you are doing and why. if you will place static only as fast solution it is bad idea in 99% of variations. in 1% time it is still bad solution but it gives you time when you need it.
The idea is to create a DOM-like tree. But there are some restrictions, that only certain types can actually contain the other.
I want to use an interface|abstract class|superclass to implement some well known js-functions as appendChild, replaceChild etc.
I'm using the classes page, block and item, where pages can contain blocks and blocks can contain either blocks or items.
Example: Page is a web page, block could be an list element and item could be an list item element.
But these objects contain more than just html-data and the concepts goes beyond just plain HTML representation. It's an overall idea of managing items, wether they have an actual representation or are just abstract objects. The concept itself works for many different hierarchies.
What I want to achieve is to reuse as much code of the parent class as possible (adding a child is basically the same for all classes) but to differ the type hints to match the allowed types to add as a child.
There are basically four ways I found out myself:
I use an interface, which allows me to type hint to the superclass but not to change these.
I use a superclass with public methods, so i can redefine the type hints (which is totally against usual practices when heriting preconditions).
I use a superclass with protected methods, which seems still being quite quirky.
I get rid of any superclass and just define almost the same class several times.
I use a method to check for the type, despite the feature of type hints.
So, if anyone is still willing to answer I'm happy for any proposition, idea or hint, which option to choose. I hope I could describe the issue well enough.
And if there is something i missed I'm thankful to hear it ;)
Code
Superclass way (works, but breaks precondition inheriting practice)
class Base {
public|protected function appendChild(Base $child) {
// do stuff
}
}
class Block extends Base {
public function appendChild(Block $child) {
parent::appendChild($child);
}
}
Interface way (Does not work. It must not)
interface Interface1 {
public function appendChild(Base $child);
}
class Base implements Interface1 {
public|protected function appendChild(Base $child) {
// do stuff
}
}
class Block extends Base{
public function appendChild(Block $child) {
parent::appendChild($child);
}
}
Edited parts are bold
Interface makes most sense to me. You can have one class that plays multiple roles, as it can implement multiple interfaces.
// you don't need any methods in the interfaces
class Foo implements Inline, Block {}
will work with both:
appendChild(Inline $foo); and appendChild(Block $foo);
and interfaces can extend each other, so there can be common interface for all your objects.
You can still use inheritance to reuse implementation, and you'll have flexibility to use inhertiance tree strictly for reuse of implementation, not limited by your page logic (you'll never be forced to make StaticSimpleton extend HeavyDatabaseyWidget).
If not interfaces, I'd go for option 5: just make appendChild call $child->canBeChildOf($this) and/or $this->accepts($child). Again, logic and implementation will be independent, and you'll have a lot of freedom with your logic.
PHP does type checks at run tmie, so use of type system doesn't buy you much anyway.
Suppose I've the following classes in my project:
class Is // validation class
class Math // number manipulation class
Now, if I want to validate a given number for primality where would be the logical place to insert my Prime() method? I can think of the following options:
Is_Math::Prime()
Math_Is::Prime()
I hate these ambiguities, the slow down my thinking process and often induce me in errors. Some more examples:
Is::Image() or Image::Is() ?
Is_Image::PNG() or Image_Is::PNG() ?
Is_i18n_US::ZipCode() or i18n_Is_US::ZipCode() or
i18n_US_Is::ZipCode() ?
In the Image example the first choice makes more sense to me while in the i18n example I prefer the last one. Not having a standard makes me feel like the whole code base is messy.
Is there a holy grail solution for organizing classes? Maybe a different paradigm?
For the Math example, I'd put the actual functionality of checking if a number is prime in the Math class. In your Is class you would put a method that would be called when a validation needs to occur. You would then use Math::Prime() from there.
With Image, that's a type check. You probably don't need to make a method for it unless you are making sure valid image data has been uploaded.
With the PNG method, same with Math. Put the actual PNG data checker algorithm in Image and make your validator method in Is call it.
The zip code example should be in your Is class only since it operates on a string primitive and probably will just use a regexp (read: it won't be a complex method, unlike your PNG checker which probably will be).
If you want to respect the SRP (http://en.wikipedia.org/wiki/Single_responsibility_principle), do the little exercice:
Select your class and try to describe what it does/can do. If you have an "AND" in your description, you must move the method to an other class.
See page 36: http://misko.hevery.com/attachments/Guide-Writing%20Testable%20Code.pdf
Other Law (there are many more) that will help you organize your classes: Law of Demeter (http://en.wikipedia.org/wiki/Law_of_Demeter).
To learn a lot and to help you make the right choice, I advice you Misko's blog (A google evangelist): http://misko.hevery.com
Hope this helps.
I don't think it's ambiguous at all. "Is" should be first in every one of those examples, and I'll tell you why: "Is" is the superset of validation operations in which Is::Math is a member.
In the case of Is::Math, what are you doing? Are you doing math operations? Or are you validating mathematical entities? The latter, obviously, otherwise it'd just be "Math".
Which of those two operations has the greater scope? Is? Or Math? Is, obviously, because Is is conceptually applicable to many non-Math entities, whereas Math is Math specific. (Likewise in the case of Math::Factor, it wouldn't be Factor::Math, because Math is the superset in which Factor belongs.)
The whole purpose of this type of OOPing is to group things in a manner that makes sense. Validation functions, even when they apply to wildly different types of entities (Prime numbers vs. PNG images) have more similarities to each other than they do to the things they are comparing. They will return the same types of data, they are called in the same kind of situations.
Everything about handling validation in itself would fit in your Is-classes:
Did it pass?
Which parts did not pass?
Should the validation errors be logged somewhere?
Zend_Validate in Zend Framework provides such an approach, maybe you can get some inspiration from it. Since this approach would have you implementing the same interface in all validation-classes, you could easily
use the same syntax for validation, independantly of which data is validated
easily recognize which validation rules you have available by checking for all classes named Is_Prime, Is_Image instead of checking for Math_Is, Image_Is all over the place.
Edit:
Why not use a syntax like this:
class Math {
public function isPrime() {
$validation_rule = new Is_Prime();
return (bool) $validation_rule->validates($this->getValue());
}
}
And thereby also allow
class Problem {
public function solveProblem(Math $math) {
$validation_rule = new Is_Prime();
if($validation_rule->validates($math->getValue())) {
return $this->handlePrime($math);
} else {
return $this->handleNonPrime($math);
}
}
}
I think there is no "The Right Answer" to the problem you stated. Some people will put Prime in Is, and some in Math. There is ambiguity. Otherwise you wouldn't be asking this question.
Now, you have to resolve the ambiguity somehow. You can think about some rules and conventions, that would say which class/method goes where. But this may be fragile, as the rules are not always obvious, and they may become very complicated, and at that point they're no longer helpful.
I'd suggest that you design the classes so that it's obvious by looking at the names where some method should go.
Don't name your validation package Is. It's so general name that almost everything goes there. IsFile, IsImage, IsLocked, IsAvailable, IsFull - doesn't sound good, ok? There is no cohesion with that design.
It's probably better to make the validation component filter data at subsystems boundary (where you have to enforce security and business rules), nothing else.
After making that decision, your example becomes obvious. Prime belongs in Math. Is::Image is probably too general. I'd prefer Image::IsValid, because you'll probably also have other methods operating on an image (more cohesion). Otherwise "Is" becomes a bag for everything, as I said at the beginning.
I don't think "is" belongs in class names at all. I think that's for methods.
abstract class Validator {}
class Math_Validator extends Validator
{
public static function isPrime( $number )
{
// whatever
}
}
class I18N_US_Validator extends Validator
{
public static function isZipCode( $input )
{
// whatever
}
}
class Image_Validator extends Validator
{
public static function isPng( $path )
{
// whatever
}
}
Math_Validator::isPrime( 1 );
I18N_US_Validator::isZipCode( '90210' );
Image_Validator::isPng( '/path/to/image.png' );
Is there a holy grail solution for organizing classes? Maybe a different paradigm?
No, that is a basic flaw of class based oop. It's subjective.
Functional programming (Not to be confused with procedural programming) has less problems with this matter, mostly because the primary building blocks are much smaller. Classless oop also deals better, being a hybrid of oop and functional programming of sorts.
Classes can be considered to be fancy types that do things, like validating themselves.
abstract class ValidatingType
{
protected $val;
public function __construct($val)
{
if(!self::isValid($val))
{ // complain, perhaps by throwing exception
throw new Exception("No, you can't do that!");
}
$this->val = $val;
}
abstract static protected function isValid($val);
}
We extend ValidatingType to create a validating type. That obliges us to create an isValid method.
class ValidatingNumber extends ValidatingType
{
...
static protected function isValid($val)
{
return is_numeric($val);
}
}
class ValidatingPrimeNumber extends ValidatingNumber
{
/*
* If your PHP doesn't have late-binding statics, then don't make the abstract
* or overridden methods isValid() static.
*/
static protected function isValid($val)
{
return parent::isValid($val)
or self::isPrime($val); // defined separately
}
}
class ValidatingImage extends ValidatingType
{
...
static protected function isValid($val)
{
// figure it out, return boolean
}
}
One advantage of this approach is that you can continue to create new validating types, and you don't get a ballooning Is class.
There are more elegant variations on this approach. This is a simple variation. The syntax may require cleaning up.