How to generate or modify a PHP class at runtime? - php

The schmittjoh/cg-library seems what I need, but there is no documentation at all.
This library provides some tools that you commonly need for generating
PHP code. One of it's strength lies in the enhancement of existing
classes with behaviors.
Given A class:
class A {}
I'd like to modify, at runtime of course and with some cache mechanism, class A, making it implementing a given interface:
interface I
{
public function mustImplement();
}
... with a "default" implementation for method mustImplement() in A class.

You can also use a Role Object pattern and good old aggregation.
Instead of having smart Entities that contain all your business logic, you make them dumb and move all the business logic into Roles that aggregate the dumb Entities then. Your behaviors are then first-class citizens living inside the Roles.
Example:
interface BannableUser
{
public function ban();
}
Having an interface with one particular behavior follows the Interface Segregation Principle. It also dramatically increases possible reuse since you are more likely to reuse individual behaviors than an Entity with an application-specific collection of behaviors.
Now to implement that, you create an appropriate Role Class:
class BannableUserRole implements BannableUser
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function ban()
{
$this->user->isBanned = true;
}
}
You still have a User entity but it's completely stripped of all behaviors. It's essentially just a bag of Getters and Setters or public properties. It represents what your System is. It's the data part, not the interaction part. The interaction is inside the Roles now.
class User
{
public $isBanned;
// … more properties
}
Now assuming you have some sort of Web UI, you can do the following in your controller:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$userId = $request->getVar('user_id');
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
You can decouple this further by moving the actual lookup of the User and assignment of the Role into a UseCase class. Let's call it Context:
class BanUserContext implements Context
{
public function run($userId)
{
$user = $this->userRepository->findById($userId);
$bannableUser = new BannableUserRole($user);
$bannableUser->ban();
}
}
Now you have all the business logic inside your Model layer and fully isolated from your User Interface. The Contexts are what your system does. Your Controller will only delegate to the appropriate Context:
class BanUserController implements RequestHandler
{
// …
public function handleRequest(Request $request)
{
$this->banUserContext->run($request->getVar('user_id'));
}
}
And that's it. No need for Runkit or similar hackery. The above is a simplified version of the Data Context Interaction architectural pattern, in case you want to further research this.

Note: OP needs PHP 5.3 (it was not tagged that way before), this question is a general outline for PHP 5.4.
You can do that with defining the interface and adding traits that contain the default implementation for those interfaces.
Then you create a new class definition that
extends from your base-class,
implements that interface and
uses the default traits.
For an example, see Traits in PHP – any real world examples/best practices?
You can easily generate that class definition code and either store it and include it or eval it straight ahead.
If you make the new classname containing all the information it consists of (in your case the base classname and the interface), you can prevent to create duplicate class definitions easily.
This works without any PHP extension like runkit. If you bring serialize into the play, you can even overload existing objects at runtime with the new interface in case they can serialize / deserialize.
You can find a code-example that has been implementing this in:
DCI-Account-Example-in-PHP / src / DCI / Casting.php (usage)

I needed a tool to edit PHP classes (specifically Doctrine Entities), I could not find it so I created one that might help you, I documented it heavily. So if you want to give it a try, I'll happily help.
Here it is, SourceEditor
It gives you an API like this:
/* #var $classEditor DocDigital\Lib\SourceEditor\PhpClassEditor */
$classEditor->parseFile($classPath);
$classEditor->getClass('a')->getMethod('b')->addAnnotation('#auth Juan Manuel Fernandez <juanmf#gmail.com>');
$classEditor->getClass('a')->getAttribute('attr')->addAnnotation('#Assert\Choice(...)');
$classEditor->getClass('a')->addAttribute($attr2);
$classEditor->getClass('a')->addUse('use DocDigital\Bundle\DocumentBundle\DocumentGenerator\Annotation as DdMapping;');
$classEditor->getClass('a')->addConst(' const CONSTANT = 1;');
file_put_contents($classPath, $classEditor->getClass('a')->render(false));

Runkit extension can help you
Runkit_Sandbox — Runkit Sandbox Class -- PHP Virtual Machine
Runkit_Sandbox_Parent — Runkit Anti-Sandbox Class
runkit_class_adopt — Convert a base class to an inherited class, add ancestral methods when appropriate
runkit_class_emancipate — Convert an inherited class to a base class, removes any method whose scope is ancestral
runkit_constant_add — Similar to define(), but allows defining in class definitions as well
runkit_constant_redefine — Redefine an already defined constant
runkit_constant_remove — Remove/Delete an already defined constant
runkit_function_add — Add a new function, similar to create_function
runkit_function_copy — Copy a function to a new function name
runkit_function_redefine — Replace a function definition with a new implementation
runkit_function_remove — Remove a function definition
runkit_function_rename — Change the name of a function
runkit_import — Process a PHP file importing function and class definitions, overwriting where appropriate
runkit_lint_file — Check the PHP syntax of the specified file
runkit_lint — Check the PHP syntax of the specified php code
runkit_method_add — Dynamically adds a new method to a given class
runkit_method_copy — Copies a method from class to another
runkit_method_redefine — Dynamically changes the code of the given method
runkit_method_remove — Dynamically removes the given method
runkit_method_rename — Dynamically changes the name of the given method
runkit_return_value_used — Determines if the current functions return value will be used
runkit_sandbox_output_handler — Specify a function to capture and/or process output from a runkit sandbox
runkit_superglobals — Return numerically indexed array of registered superglobals

You can look: https://github.com/ptrofimov/jslikeobject
Author implemented dynamic JS-like objects with support of inheritance.
But it is more like a joke than real proposition.

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

What's a good example for making use of an anonymous class in PHP7

As I looked for the new PHP7-features I stumbled upon anonymous classes.
I didn't understand when they should become useful, and looked for an example.
I read this article, but I don't see the benefits of this feature.
In the last section before the conclusion they wrote the following about the advantages:
One advantage is that we no longer need the named extension. Normally the named extension would be hidden away in some included file, if you ever needed to see how it is defined you have to start searching for it. With anonymous classes the definition is in the same place the object is created.
On the other hand, I see a big disadvantage because you can use this anonymous class only at the place it is defined.
Can someone please explain when this feature is useful?
Especially if it can help when building custom systems or extending a CMS like WordPress (preferably in German, although English is also welcome).
Anonymous classes could be useful in writing implementation classes for listener interfaces, so you don't need to create a file or a generic class just to implement once.
One of the most elegant things about anonymous classes is that they
allow you to define a one-shot class exactly where it is needed. In
addition, anonymous classes have a succinct syntax that reduces
clutter in your code. Java in a nutshell
So, you can have an anonymous implementation of an interface or even extend a class, with additional properties or overwritten methods.
Example:
return new class(10) extends SomeClass implements SomeInterface {
private $num;
public function __construct($num)
{
$this->num = $num;
}
};
Another situation:
Provide a simple implementation of an adapter class. An adapter class is one that defines code that is invoked by some other object. Take, for example, the list() method on a class called File. This method lists the files in a directory. Before it returns the list, though, it passes the name of each file to a FilenameFilter object you must supply. This FilenameFilter object accepts or rejects each file. When you implement the FilenameFilter interface, you are defining an adapter class for use with the $file->list() method. Since the body of such a class is typically quite short, it is easy to define an adapter class as an anonymous class.
$file = new File("/src");
// Now call the list() method with a single FilenameFilter argument
// Define and instantiate an anonymous implementation of FilenameFilter
// as part of the method invocation expression.
$filelist = $file->list(new class extends FilenameFilterClass {
public function accept(File $f, string $otherInfo) {
return pathinfo($f, PATHINFO_EXTENSION) === ".php";
}
});
Some nice basic understanding and use about anonymous classes could be found on Java (I know its not PHP, but it helps on understanding) examples at https://www.geeksforgeeks.org/anonymous-inner-class-java/
I should use a anonymous class only if this class is not used anywhere else and if these class isn't changed since the first coding.
So for example a database class could maybe a candidate for using a anonymous class because it should be use only once and could be included in any other php file. In most cases the data for accessing the database is in the config file. Therefore this file should be loaded for every php file that is using the database when you want to avoid the hard coding of the database params (which is a bad idea). If you coded these class as an anonymous class in the config file you have eliminated one include whithout losing the maintainance.

PHP - if all methods in abstract class are abstract then what is the difference between interface and abstract class

An Abstract Class may and may not have abstract methods but an interface has unimplemented methods only. So what is the difference and advantage of using an interface if my abstract class has all of its methods marked as abstract?
Interfaces and Abstraction
The real power of use can be revealed in huge APIs with massive amount of classes that follow a well-thought flexible structure for future coding. Whether it may happen or not - you never know whether a code will be extended. Interfaces are merely used for semantic reasons. Imagine, you extend a deprecated version of an API and have the job to edit/alter/implement/update/improve/extend/modify the code to bring it up to date, whatever the reason is. You'd end up being frustrated if you did not think forward.
Small APIs can be made without the interfaces and that's where most people think interfaces were unnecessary. But then they lose their flexibility as soon as they become larger. They provide you a contract with classes which reminds you what is needed and to keep the overview. Interfaces must have public methods, if you have protected or private ones, just return them in a public method of a class with interface implemented..
Like you already explained, interfaces demand particular methods to be implemented, abstract classes don't demand it since you most likely extend them anyway. Methods can be re-defined and abstract methods MUST be defined in child classes. Methods mentioned in an interface only tells you that classes that have a contract with an interface must have these defined. It could be multiple interfaces, you don't inherit from them like you would do it with abstract classes.
Think like this way
The logic in it is to predict the future in what you are planning to build. Be it in architecture, infrastructure or mass production in factories. Just like the way you sort items like bookmarks, books, images in a folder. Because you know it would take longer to find a particular image if you didn't sort it. The semantic purpose of abstraction and interface is similar, especially in huge APIs.
An interface reperesents a frame of possibilities and requirements.
An abstraction preserves conceptual information that is relevant in a derived context.
I'll show you a typical structure for a start of an API with simplified contents wherein interfaces and abstract classes have a real point of usage for future extension.
/* Considering, this project will be widely expanded up to huge complexity.
This is a flexible base structure, for developers working in team. Imagine
there could be lots more variation of styles for certain purposes. */
// OOP STRUCT
// You might want to define multiple interfaces to separate the project
interface iString {
// These methods MUST be defined or else the developer receives an error
public function getContent();
public function description($desc);
}
/* Devs might want to add an additional method later on.
Traits are useful for quick use. (optional) */
trait desc {
private $desc;
public function description($desc) {
return $this->desc;
}
}
/* This is the base class for the content which requires a declaration
of methods being described in the interface */
class contents implements iString {
use desc; // use the method defined in a trait
private $str;
public function __construct($str) {
$this->str = $str;
}
public function getContent() {
return $this->str;
}
}
/* Or devs often consider abstract classes as the real base of the whole project/app.
Abstract classes allow the use of methods that can be modified/declared for further use in derived classes.
Interfaces can't do that */
abstract class stylize {
private $str;
// This typehint below makes sure that this value is assigned on interface
public function __construct(iString $str) {
$this->str = $str;
}
public function style() {
return $this->str->getContent();
}
abstract public function getContent();
}
// EXTENDED CLASSES
class bold extends stylize {
// Extended classes have to define abstract methods inherited from an abstract class. Non-abstract methods are not needed.
public function getContent() {
return "<strong>".parent::style()."</strong>";
}
}
class underline extends stylize {
public function getContent() {
return "<u>".parent::style()."</u>";
}
}
class upperCase extends stylize {
public function getContent() {
return strtoupper(parent::style());
}
}
// PROCEDUAL OUTPUT
// A tiny shortcut
$e = function($desc,$str) { echo $desc.": ".$str->getContent()."<br>"; };
// Content being used
$content = new contents('Hello World.');
$e("Normal",$content);
// Content being styled
$bold = new bold($content);
$underline = new underline($content);
$upper = new upperCase($content);
// Renders content with styles
$e("Bold",$bold);
$e("Underline",$underline);
$e("Uppercase",$upper);
Conclusion
Applying styles of text contents as an example is probably not appealing enough. But apart from this, it remains the same - if it does what it should do, then it's done. Like as if I would build an expandable eMail configuration API as a module for a CMS. This structure has a semantic process in proper coding.
Tipps
I'd suggest you to keep learning in small projects with this pattern, even if you think interfaces are not worth it. Keep doing this until you have it inside. My own personal advice for you:
If you think you have no idea where to start and what project to try it on, then try real world examples just follow this logic:
Vehicles (abstract class)
-> Ferrari (extended class)
-> Truck (extended class)
both have wheels (property)
both must be able to drive (method)
they perform a 1mile match race on a street (abstract method)
one is a slowpoke (extended property)
one is red one is blue (extended property)
and later a 3rd one comes and its a train (extended class)
who's going to win (some method)
Instantiate all vehicles and maintain privileges over interface and
abstraction.
...something like this...
Usually, classes containing huge bodies are supposed to be separated in single files + include these + define a namespace. Else wall of code would make you or someone else tired. Use Eclipse, best app for maintaining OOP.
Also, if it fits for your project, use phUML if you have Linux Ubuntu. It generates a graphical diagram for your current build if you have a lot of relating classes.
phUML is an API in PHP based on UML. It is an open-source project which generates any visual schemes for almost any popular programming language. I use it a lot, not just for PHP. Simply clone it at Github or download from dasunhegoda.com and follow installation guide there. This could interest you also: Typehinting on Interfaces
An Abstract Class allows for "partial implementation" (see the template method pattern), but in this case, if all methods are abstract, you don't see that benefit. One other thing you can do is include fields, you're not just limited to methods.
Remember, there's a conceptual difference between an "abstract method" and the contract defined by an interface. An abstract method has to be overridden by a subclass which is done through inheritence implementation. Any polymorphic calls (downcasting) will require one superclass per class or it would hit the diamond inheritance problem. This kind of inheritence based tree structure is typical of OO design.
As a contrast, an interface provides a signature of a contract to fulfil. You can fulfil many interface's needs as long as you retain the signature as there is no question of going back up the class hierarchy to find other implementations. Interfaces don't really rely on polymorphism to do this, it's based on a contract.
The other thing of note is you may have "protected" abstract methods, it makes no sense to do such a thing in an interface (in fact it's illegal to do so).
If an abstract class has all of its methods defined as abstract then you have to define its body in any subclasses and it displays similar behavior as interface.
Benefit :
Using interface instead of abstract class, you can implement more than one interfaces while using abstract class you can only extend one class at a time.
EDIT
Another difference I found about this is abstract class can have constructor while interface can't have.
REF: What is the use of constructor in abstract class in php

Is this a pattern, or similar to a pattern, and what's its name

I have 3 classes:
an interface class that defines a few methods
2 classes which implement that interface Class_A and Class_B
I then have a class which basically chooses which class (A or B) to instantiate based on some condition
class Chooser
{
public static function choose($condition)
{
$class = 'Class_' . ucfirst($condition);
return new $class();
}
}
I then call the static choose method and it returns an instance of the right class (A or B)
Chooser::choose($condition);
My questions:
first of all, is this a valid pattern (or close to a pattern), and what is its name
if it's close to a pattern, how can I modify so it's a proper pattern
third, the Chooser class is so simple. I could have that logic in my original code instead of Chooser::choose($condition);. If I do this, would it now mess with the pattern?
Yes, your example fits in as Factory Pattern. It's one of the creational pattern.
In your original code, do all the coding based upon your interface. The chooser would be responsible for making the correct choice of class to instantiate. You would achieve high separation of concerns by doing it.
Read more about it here.
http://www.oodesign.com/factory-pattern.html
I would not call it a pattern as it's concrete code. Patterns are just descriptions of what can be done how. It looks a bit like an implementation of the Factory pattern and if you call it Factory, most users might get a quicker understanding of what it is for.
However it's probably better described as parametrized object creation, as you don't verify that the class it generates implements a specific interface, which is part of a common Factory pattern.
That ensures that the function returns a type with a specific interface.
class Chooser
{
/**
* #return interface
*/
public static function choose($condition)
{
$class = 'Class_' . ucfirst($condition);
if (!is_a($class, 'interface'))
return NULL;
return new $class();
}
}
This needs some specific PHP versions and can be influenced by bugs in PHP because of is_a. There are alternative ways to check whether a specific classname implements an interface though. I leave this as an exercise.
You need also decide whether the chooser() function returns NULL if condition does not lead to an object or if it should throw an exception.

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).

Categories