3

In order to better organize my code in a PHP project (a simple CMS) I'm considering moving most of my System functions to an abstract class as static members. Aside from the organizational and syntactical benefit from it, the only other reason would be to store references to datasource objects, etc., as static members also.

Rules are made to be broken when necessary, but I want to solidify my understanding of better (read best) patterns and practices.

I suppose this question is open ended, but I was wondering if anyone had suggestions, or could perhaps suggest some reading material, so I could explore my options and what would be considered 'best practices'.

An example of this in my code would be functions for managing permissions. For any given request, permission checks may be necessary to ensure the requesting user has sufficient privileges for the operation. So functions such as getAllPermissions(), getGroupPermissions(), addGroupPermissions(), etc., are floating around. Should these be encapsulated within a PermissionsManager class, necessary to instantiate, and if so, where do I stop? Am I on the right track moving them to a pseudo-global space within an abstract class as static methods? Should I just leave the declarations in global scope? Where do appropriate class responsibilities end and 'god-class' takeovers begin? What color socks should I wear?

I just can't seem to wrap my head around this, and it's slowing my productivity. I don't want to idle any longer on modeling, because despite it's obvious benefits, I've certainly destroyed a few trees sketching out object-interaction diagrams. And my wastebasket is full.

Dan Lugg
  • 20,192
  • 19
  • 110
  • 174

2 Answers2

3

suggest some reading material

Have a look at SOLID and GRASP and this answer of mine: Php design patterns

Should these be encapsulated within a PermissionsManager class

Yes. If these functions are related, group them. Also have a look at this Wikipedia Article about Role-Based Access Control Lists and have a look at the various questions about ACLs in PHP on StackOverflow.

Am I on the right track moving them to a pseudo-global space within an abstract class as static methods?

No, you should avoid static if possible. Statics lead to tight coupling and introduce dependencies on the global scope leading to less maintainable applications which leads to a longer time to deliver (e.g. bugfixes and new features) which leads to higher overall cost and less return of investment.

Should I just leave the declarations in global scope?

If you do changes to your application, you should be able to explain the benefit. If you think your application can benefit from refactoring this code, then refactor it. You should stop when there is no return of investment.

Where do appropriate class responsibilities end and 'god-class' takeovers begin?

Since you should stick to the single responsibility principle, any responsibility beyond one is a code smell (though sometimes it may make sense to have more than one). I found this description of a GodClass easy to comprehend.

What color socks should I wear?

That depends on the shoes you intend to wear with them. In general, I find dark socks to be the best choice for most occasions and shoes, while white socks are a No-Go most of time.

I don't want to idle any longer on modeling

Some thinking before you start is good. Understanding the problem and the domain you want to solve, is necessary to make decisions. But you should start with solving the problem eventually. Only working code (even poorly designed one) yields business value. Pristine up-front designs wont survive the reality of a project anyway.

Community
  • 1
  • 1
Gordon
  • 312,688
  • 75
  • 539
  • 559
  • 1
    Outstanding! Seems the fellow with 14 static methods found himself in the place I was headed, as my proposed abstract `System` class would have been a glorified toolbox. I'll be doing some careful reading of the suggestions you've given. – Dan Lugg Dec 09 '10 at 09:39
  • I suppose the only other question I have then, is seeing as something like an ID generator/validator function set (128 bit binary IDs) is quite 'global' in its use, would dependency injection (which I'm beginning to read about) be my best choice for ensuring it's availability to other classes? One would think passing around an instance of it would be a bit tedious. No class? Singleton perhaps? (awaits lightning strike) – Dan Lugg Dec 09 '10 at 09:44
  • 1
    @Tomcat If you want a loosely coupled and highly maintainable system, then the "textbook answer" is make it into a class (or maybe a Lambda function) and inject it. Dont make it a Singleton. They dont have use in PHP because there is no shared application memory. Forget they exist. Yes, it might be tedious to inject. This is where you have to decide if an easier but less "clean" solution would yield more benefit. Like I said, produce working code first and foremost. You can still refactor later. – Gordon Dec 09 '10 at 09:53
  • Thanks alot **Gordon**, your insight is greatly appreciated! I'll be following your answers on other topics of interest. – Dan Lugg Dec 09 '10 at 10:05
1

As a general advice, you should avoid static functions at any price, at least, as long as you follow the OOP route. In OOP, your code is much like a natural language, and function calls follow the "subject-verb-object" phrasal structure: "someone does something (with something else)". "Unbound" (global and static) calls are like a phrase without a subject, "this is being done with something", which, of course, raises some immediate questions - who is the actor of this action? who is responsible for the consequences? how can we substitute this action with something else, for testing purposes? etc etc

This natural language metaphor is extremely helpful when you run into design problems. Write down your problem in simple phrases. Underline subjects, verbs and objects. Rewrite the text in a programming language, following the $subject->verb($object) pattern - and voilà, you're done.

Back to your permissions example: you're asking if a user $u has a permission $p for an entity $e. In a natural language you can express this in three different ways, depending upon what you like to be a subject:

  • "Can Joe read foo.txt?" (subject = user)
  • "Is foo.txt readable by Joe?" (subject = entity)
  • and even "Is read permission granted to Joe for foo.txt?" (subject = permission)

All three ways sound fine, and can be immediately translated to OOP-php code:

if ($user->can_read($file)) ...
if ($file->is_readable_by($user)) ...
if ($read_permission->for_entity($file)->is_granted_to($user)) ...

No need for static functions.

user187291
  • 53,363
  • 19
  • 95
  • 127
  • Thanks **stereofrog**, interesting perspective with the natural language metaphor. It is very clear. – Dan Lugg Dec 09 '10 at 10:08