PHP OO Design: extend static class or instance class? - php

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.
I have an application which defines certain actions on common object types.
For example, you can have forum post and images. For each forum post and image you can do the following actions: recommend, comment, rate.
I have currently defined a static class
class CoreObjectUtil
{
protected static $_objObjKey = null;
protected static $_objTypeKey = null;
public static function getComments (...) {...}
public static function getCommentsArray (...) {...}
public static function getRatings (...) {...}
public static function getRatingsArray (...) {...}
}
which is then subclassed like this
class ForumPostUtil extends CoreObjectUtil
{
protected static $_objObjKey = 'forumpost';
protected static $_objTypeKey = 'FP';
}
to provide the relevant functionality for forum posts. The 2 parameters suffice to let the generic code in CoreObjectUtil know what to do for each object type for which these functions are applicable.
To use these functions, I am calling the selectPostProcess() class in my instance classes like this:
public function selectPostProcess ($data)
{
$data = ForumPostUtil::mergeRatings ($data);
$data = ForumPostUtil::mergeComments ($data);
...
}
This works well and keeps the main code centralized in the CoreObjectUtil class with its subclasses providing the data setup to let the code in CoreObjectUtil know what to do.
An alternative approach would be to move the code from CoreObjectUtil into a base instance class which is then inherited in my instance classes. So rather than calling static methods from CoreObjectUtil I would be doing method calls like $this->getComments().
Either approach would work just fine from a functionality type point of view. I'm wondering however what ObjectOriented design guidelines and experienced ObjectOriented developers think of these two approaches. Which way of doing this is preferable and why?
I would appreciate any thoughts/insights on this matter. I can code either way without problem, but I'm having a tough time deciding which route to take.

That code you have now is, I think, the most procedural approach ever posing as OOP i.e what you have now is at the opposite side of OOP. Using the class keyword doesn't make it OOP.
First of all, you should forget about static, it's not that it's bad ot use but it's so easily abused that you really have to try first if the functionality can belong to an object modelling a domain concept (in your case forum related). Only if it doesn't make sense this way, you'll have it as a static method somewhere in a utility class.
Truth be told you have to redesign yur app around the OOP mindset, that is to define classes with behaviour which model a specific concept or process and which have only one responsaiblity. More over you should not mix things like business objects (object which model the forum concepts) with persistence concerns i.e don't put in the same object business functionality and database access. Use a separate class for accessing storage.
Use the Repository pattern to separate business layer from the persistence layer. Try not to mix together create/update functionality with querying IF it complicates things. Use a separate read model specifically for querying in that case.
The code you show us is about querying. You can have a simple DAO/Repository (call it what you want in this case) like this
class ThreadViewData
{
public $Id ;
public $Title;
public $Comments; //etc
}
class ThreadsQueryRepository
{
//we inject the db access object , this helps with testing
function _construct($db) { }
public function GetThread($id){ } //this returns a ThreadViewData
}
The postPRocess functionality is a service that can Merge Ratings and Comments. But maybe the merge functionality is more suitable to the Rating and Comment objects. I don't know the domain to actually give a valid suggestion.
Point is, you have to think in objects not in functions and right now all you have is functions.

Related

What is the purpose of using traits to define functions for an interface

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

PHP MVC - Model needs to access data from another model

I have built a small PHP MVC framework and just want to clarify the best way to get data from one model into another. For example:
I have a Users_model that contains a method called get_users().
I also have Communications_model that needs to get specific or all user data and as such needs to access the get_users() method from the Users_model.
Is it best practice to:
a) Instantiate the Users_model in a controller and pass the data from the get_users() method into the Communications_model?
b) Instantiate the Users_model inside the Communications_model and run get_users() from there, so it can be accessed directly?
c) Another way?
Many thanks for any help.
It depends of your motive behind this.
If you want effect on result, then using well know library, like Doctrine etc. should be your choice.
If you want to learn design patterns, then you should get read about ActiveRecord or DataMapper + Repository patterns. Then implements both and check out.
If you want your code, this way - ORM should represent relations of data, then you should ask what it more important? If you menage communication (bus, train), then user can be there assigned and getting users from communication is OK. If user have communication (like car), then relation is reversed.
All depends, what is you motive behind this. Using library, like Doctrine, could you help you running you application. If you want learn design patterns, then check out both options to get some experience.
What you call "users model" is a repository. And what you call "communication model" looks like a service.
Your communication service should have the user repository passed in constructor as a dependency.
I honestly think, that a huge part of your confusion is that you try to call all of those things "models". Those classes are not part of the same layer. You migth find this answer to be useful.
All are possible ways but what I usually do is, whenever there is any function that I think would be reused a number of times by a number of objects, I declare it as static.
It would save the effort of playing with object declaration and would be easily accessible by ClassName::function();
Again, it's a design choice, usually objects are declared right there in the controller and used as per the need but just to save declaration of objects again and again I follow the approach of declaring function static.
The simple principle here is using the __construct() (constructor) to build the object with the relevant properties from the Database. The User Model will have a static function (therefore accessible through any scope) to create an array of instanced objects by simply passing the model data through a new self() which returns the instance.
The concept is you end up with an array of User_Model instances each being a build of the Database columns to properties. All that's left is to create the Database Model and the functions to retrieve the columns and data.
class Communications_Model {
private $_all_users;
public function getUsers() {
$this->_all_users = Users_Model::loadAllUsers();
}
}
class Users_Model {
private $_example_property;
public function __construct($user_id) {
$data = SomeDatabaseModel::getConnection()->loadUserFromDatabase((int)$user_id);
$this->_example_property = $data['example_column'];
}
public static function loadAllUsers() {
$users = array();
foreach(SomeDataModel::getConnection()->loadAllUsers() as $data) {
$users[] = new self($data['user_id']);
}
return $users;
}
}
Of course, now, you have a $_all_users; property that has an array of instanced User Models containing the data.

When should I use static methods?

I have a class that is containing 10 methods. I always need to use one of those methods. Now I want to know, which approach is better?
class cls{
public function func1(){}
public function func2(){}
.
.
public function func10(){}
}
$obj = new cls;
$data = $obj->func3(); // it is random, it can be anything (func1, or func9 or ...)
OR
class cls{
public static function func1(){}
public static function func2(){}
.
.
public static function func10(){}
}
cls::func3(); // it is random, it can be anything (func1, or func9 or ...)
It is an interesting subject. I'm gonna give you a design oriented answer.
In my opinion, you should never use a static class/function in a good OOP architecture.
When you use static, this is to call a function without an instance of the class. The main reason is often to represent a service class which should not be instantiated many times.
I will give you 3 solutions (from the worst to the best) to achieve that:
Static
A static class (with only static functions) prevent you from using many OOP features like inheritance, interface implementation. If you really think of what is a static function, it is a function namespaced by the name of its class. You already have namespaces in PHP, so why add another layer?
Another big disadvantage is that you cannot define clear dependencies with your static class and the classes using it which is a bad thing for maintenability and scalability of your application.
Singleton
A singleton is a way to force a class to have only one instance:
<?php
class Singleton {
// Unique instance.
private static $instance = null;
// Private constructor prevent you from instancing the class with "new".
private function __construct() {
}
// Method to get the unique instance.
public static function getInstance() {
// Create the instance if it does not exist.
if (!isset(self::$instance)) {
self::$instance = new Singleton();
}
// Return the unique instance.
return self::$instance;
}
}
It is a better way because you can use inheritance, interfaces and your method will be called on an instanciated object. This means you can define contracts and use low coupling with the classes using it. However some people consider the singleton as an anti pattern especially because if you want to have 2 or more instances of your class with different input properties (like the classic example of the connection to 2 different databases) you cannot without a big refactoring of all your code using the singleton.
Service
A service is an instance of a standard class. It is a way to rationalize your code. This kind of architecture is called SOA (service oriented architecture). I give you an example:
If you want to add a method to sell a product in a store to a consumer and you have classes Product, Store and Consumer. Where should you instantiate this method? I can guarantee that if you think it is more logical in one of these three class today it could be anything else tomorrow. This leads to lots of duplications and a difficulty to find where is the code you are looking for. Instead, you can use a service class like a SaleHandler for example which will know how to manipulate your data classes.
It is a good idea to use a framework helping you to inject them into each others (dependency injection) in order to use them at their full potential. In the PHP community, you have a nice example of implementation of this in Symfony for instance.
To sum up:
If you do not have a framework, singletons are certainly an option even if I personally prefer a simple file where I make manual dependency injection.
If you have a framework, use its dependency injection feature to do that kind of thing.
You should not use static method (in OOP). If you need a static method in one of your class, this means you can create a new singleton/service containing this method and inject it to the instance of classes needing it.
The answer depends on what those methods do. If you're using them to mutate the state of the object at hand, you need to use the instance method calls. If they're independent functionality, then you can use the static versions, but then I'd question why they're part of a class at all.
So, there is a very basic difference in static methods.
To use static functions, you don't need to initialise the class as an object. For example, Math.pow(), here .pow() (in Java; but the explanation still holds) is a static method.
The general rule is to make the helper methods static.
So, for example, if you have a Math class, you wouldn't want to fill the garbage collector with classes which just help other, more important, classes.
You can use it as dynamic initializers, if you please!
Let's say you have a class RSAEncryptionHelper, now you can generally initialize it without any parameters and this will generate an object with a key size of (say) 512 bits; but you also have an overloaded object constructor which gets all of the properties from other classes:
$a = new RSAEncryptionHelper::fromPrimeSet(...);
Within a PHP class you can use class/methods/attributes: Abstract, Static, Private, Public, etc ...
The best way is to know how to mix them all within a class depending on the need, I will give you a basic example:
Within the Person class, you have private and public methods, but you have a method called "get_nationality" so this is a function that you need somewhere else but you do not have the Person class installed yet, so this method you put it as STATIC in this way you can invoke the "get_nationality" method without installing any Person class, this makes your business model more optimal and in turn now resources in the CPU.
Static functions are also very useful but
I usually make traits when I have to create functions that are independently related to a class.
I don't know if this approach is better or not but most times I found it useful.
Just sharing my approach here so that I can learn more about its pros and cons.
You can think a factory. You will give some materials, it will give you same output. Then you should use static function.
class ProductDetails
{
public static function getRow($id, PDO $pdo): SingleProduct
{
// this function will return an Object.
}
}
I am not defining the Object here. Just where you need a Single Product you can simply do that ProductDetails::getRow(10, $pdo);

PHP Structure - Interfaces and stdClass vars

I'm building a class to handle Paypal IPNs as part of a project, and since I already know i'm going to need to use it again in at least two more upcoming jobs - I want to make sure I structure it in a way that will allow me to re-use it without having to recode the class - I just want to have to handle changes in the business logic.
The first part of the question is re. interfaces. I haven't quite grasped their usefulness and when/where to deploy them. If I have my class file ("class.paypal-ipn.php"), do I implement the interface in that file?
Here's what i'm working with so far (the function list is incomplete but its just for illustration):
CLASS.PAYPAL-IPN-BASE.PHP
interface ipn_interface {
//Database Functions
// Actual queries should come from a project-specific business logic class
// so that this class is reusable.
public function getDatabaseConnection();
public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb");
public function dbQuery($SQL);
//Logging Functions
public function writeLog($logMessage);
public function dumpLogToDatabase();
public function dumpLogToEmail();
public function dumpLogToFile();
//Business Logic Functions
private function getTransaction($transactionID);
//Misc Functions
public function terminate();
}
class paypal_ipn_base {
//nothing to do with business logic here.
public function getDatabaseConnection() {
}
public function setDatabaseVars($host="localhost",$user="root",$password="",$db="mydb") {
}
public function dbQuery($SQL) {
}
}
CLASS.PAYPAL-IPN.PHP
final class paypal_ipn extends paypal_ipn_base implements ipn_interface {
//business logic specific to each project here
private function getTransaction($transactionID) {
$SQL = "SELECT stuff FROM table";
$QRY = this->dbQuery($SQL);
//turn the specific project related stuff into something generic
return $generic_stuff; //to be handled by the base class again.
}
}
Usage
In this project:
Require the class files for both the base, and the business logic class.
Instatiate *paypal_ipn*
Write code
In other projects:
Copy over the base IPN class
Edit/rewrite the business logic class *paypal_ipn* within the constraints of the interface.
Instantiate *paypal_ipn*
Write code
So as you can see i'm literally just using it to define groups of related functions and add comments. It makes it easier to read, but of what (if any) other benefit is it to me - is it so that I can pull the extender and the base class together and force errors if something is missing?
stdClass Question
The second part of the question is building on the readability aspect. Within the class itself there is an ever increasing number of stored variables, some are set in the constructor, some by other functions - they relate to things such as holding the database connection vars (and the connection resource itself), whether the code should run in test mode, the settings for logging and the log itself, and so on...
I had started to just build them as per usual (again, below incomplete & for illustration):
$this->dbConnection = false;
$this->dbHost = "";
$this->dbUser = "";
$this->enableLogging = true;
$this->sendLogByEmail = true;
$this->sendLogTo = "user#domain.com";
But then I figured that the ever growing list could do with some structure, so I adapted it to:
$this->database->connection = false;
$this->database->host = "";
$this->database->user = "";
$this->logging->enable = true;
$this->logging->sendByEmail = true;
$this->logging->emailTo = "user#domain.com";
Which gives me a much easier to read list of variables when I dump the entire class out as I code & test.
Once complete, I then plan to write a project specific extension to the generic class where i'll keep the actual SQL for the queries - as from one project to another, Paypal's IPN procedure and logic won't change - but each project's database structure will, so an extention to the class will sanitize everything back into a single format, so the base class doesn't have to worry about it and will never need to change once written.
So all in all just a sanity check - before I go too far down this road, does it seem like the right approach?
if you are using a class autoloader, which I highly recommend, you would not want to keep the interface and the class in the same file so that the interface can autoload without needing to first load this one class that implements it.
For more info on autoloading:
http://php.net/manual/en/language.oop5.autoload.php
another thing you may want to consider is that a given class may impliment multiple interfaces, and multiple classes may implement the same interface.
interfaces are primarily used for various design patterns, to enforce rules, and to decouple a class from any dependent classes. when you decouple a class from its dependencies, it makes it much easier to modify code at a later time.
for instance, let's say you have a class A that takes in another class B as an argument, and this class is spread throughout your code. you want to enforce that only a class with a specific subset of methods can be accepted as this argument, but you do not want to limit the input to one concrete class and it's decendants. in the future, you may write an entirely different class that does not extend class B, but would be useful as an input for class A. this is why you would use an interface. it is a reusable contract between classes.
some would argue that since PHP is a dynamic language, interfaces are an unecessary complication, and that duck typing may be used instead. I find in large multi-user code bases however, that interfaces can save a lot of time, letting you know more about how one class uses another, without having to study the code in depth.
if you find yourself with a large list of variables that you have to pass around between objects or functions, they often do end up deserving a class of their own, but each case is different.
-- dependency injection example --
class A implements AInterface {
public function foo($some_var) {}
}
interface AInterface {
public function foo($some_var);
}
class B {
protected $localProperty;
// inject into the constructer. usually used if the object is saved in a property and used throughout the class
public function __construct(AInterface $a_object) {
$this->localProperty = $a_object;
}
// inject into a method. usually used if the object is only needed for this particular method
public function someMethod(AInterface $a_object) {
$a_object->foo('some_var');
}
}
you can now see that you can write another class that impliments a foo method (and the AInterface) and use that within class B as well.
as a real world example (used often), say you have a database class with particular methods that interact with the database (getRecord, deleteRecord). now lets say at a later time you find a reason to switch database rdbms. you now need to use entirely different SQL statements to accomplish the same goals, but since you used an interface for your type hinting, you can simply create a new class that impliments that interface, but impliments those same methods in entirely different ways as it interacts with a different rdbms. when creating this new class, you will know exactly what methods need to be written for this new class in order to fit into the same objects that need to use a database object. if you use a container class that you use to create objects and inject them into other objects, you would not need to change too much application code in order to switch databases classes, and therefore switch database rdbms. you could even use a factory class, which could limit your changes to one line of code to make this type of change (in theory).

How to represent an object and map between different sources/locations

I will be building a system where a particular object will originate from a web service (SOAP based). It will then be displayed on a web page (via PHP). Under certain circumstances we'll store a copy with some additional information in a local MySQL database. And from there it will be batch processed into Salesforce CRM (again via PHP). We may also subsequently pull the object out of Salesforce for display online. So alot going on. For the most part the object is the same with each subsequent node in the system likely adding a couple of fields specific to it, unique ids mainly.
I'd initially toyed with the idea of encapsulating all the necessary functionality into the one class in PHP which would deal with reading and writing from each of the appropriate sources. This felt like it was over complicating the class, and not a good approach.
I then looked at having just a container class, with no real functionality attached beyond getters and setters. Then creating separate functionality outside of this to deal with the reading and writing between the different sources, simple enough code although tedious to map between all the different field names across the different sources. There is probably a design pattern or two that apply here, but I'm not familiar with them. Any and all suggestions on how to approach this appreciated.
What you are looking is Adapter pattern. You can keep your existing code till you completely change all the classes.
I'd suggest to use a composite memento serializable into XML.
I think they may be several ways to handle that. #EGL 2-101 adapter idea is one way to do it.
Basically, you have several sources, which in O.O. jargon, are different objects. But, you want to treated like if they where a single object.
You may want to make a single class for each source, test the "connection", as if each case was the only way you where going to work with. When you have several of that classes, try to make all classes share some interface, methods or properties:
class AnyConnection
{
public function __construct() {
// ...
}
public function read() {
// ...
}
} // class
class SOAPObject extends AnyConnection
{
public function __construct() {
// ...
}
public function read() {
// ...
}
} // class
class MYSQLObject extends AnyConnection
{
public function __construct() {
// ...
}
public function read() {
// ...
}
} // class
class SalesObject extends AnyConnection
{
public function __construct() {
// ...
}
public function read() {
// ...
}
} // class
Later, use a single class to wrap to all of these source classes.
class AnyObject extends AnyConnection
{
$mySOAPObject;
$myMYSQLObject;
$mySalesObject;
public function __construct() {
// ...
}
public function read() {
// ...
}
} // class
Later, add the code, to select which "connection" you want.
Why not separate data and operations?
Contain the core information into a class C. When web services sends this class, it is encompassed in an object of some class W. The web service pulls C and sends it to persistence layer, which creates and stores P that internally contains C, et.c.,
Akin to how data flows over a TCP/IP stack...
The way I see this after thinking about it a bit would be pretty much a class to play with your object and then serialize it.
I'd probably use something like this:
<?php
class MyObject
{
protected $_data;
public function __construct($serializedObject = null) {
if(!is_null($serializedObject)) {
$this->_data = json_decode($serializedObject);
}
}
public function __get($key) {
return $this->_data[$key];
}
/* setter and other things you need */
public function encode() {
return json_encode($this->_data);
}
public function __toString() {
return $this->encode();
}
}
Then just use it to pass it serialized to your different web services.
I think JSON would do a pretty good job on this one, because you can easily unserialize it fast in so many programming languages and it's so much lighter than XML.
DataMapper pattern is that what you're looking for.
You can have one mapper for each storage mechanism that you use and use them all with one object that represent data to business logic.
Is seems your problem is more of an architectural / design decision that pure implementation detail. (I haven't done PHP for a long while and do not know salesforce but other CRM systems)
I believe the technique/pattern that will work for you is the use of a staging area. This helps especially if you have changing integration needs and also when your source data looks different from your system model or when you have different sources to integrate from. Thus, you import into the staging area and then from the staging into your system. At each place you naturally have to map (can use metadata) and maybe transform/translate data. There will be initial effort to build this, but once it's done the step from staging to your system stays quite static/stable.
Using meta data mapping can address flexibility concerns but adds a bit of complexity on implementation. It all depends on the skills and time you have at hand for your project.
I would not have any association between the objects at all. They are used for different purposes but looks similar. period.
In .NET we use a library called automapper to copy information between different classes (like a business object and a DTO). You can build something similar in PHP, either by using get_object_vars or the reflection API.
myCopyApi.copy($myDTO, $myBO);
Say you retrieve a Car from the webservice. You can store it in a WebserviceCar, which has a property car.
Now, if you want to store that Car in the database, put it in a DatabaseCar, which also has a property car. If you want to put it in Salesforce, put it in a SalesforceCar object, which has a property car.
This way, you have one object which has the common fields and several objects which have storage-specific information.
Assuming that you are thinking about storing the actual object (serialized,encoded or whatever) in a field in the database: From my point of view the object it is never the same in two applications, as business-wise, it serves different purposes. Doing this is a kind of "cutting short" in a case where is no room for "cutting short".
Remember that mainly class represents a "category of objects" which all share same properties and behaviours. So let each application use it's own class as their purpose requires it. What can be created although is, as others suggested and as you thought, the creation of an Adapter or Factory which can be used in all the implied applications as it serves the same business purposes "translation" of objects.
Adapter pattern
Factory pattern

Categories