I need some advice on how I can proceed with this issue.
Using PHP
An example would be:
class BuilderClass {
function getClass($id, $some, $vars){
$dbResult = new db_Class::getDbRows($id, $some, $vars);
foreach(...)
// Build something from the database values
return self;
}
}
So what I want to do is to create a test case where I somehow mock the db results.
I have not found any great way to do this, please point me in the right direction or similar to get this working for me.
I could change something within the builder itself for example call a class that runs the function: FunctionRunner::runStaticFunction("db_Class", "getDbRows", $args, $something_else); But at the moment I don't know if that is possible neither. Any research articles that cover this or any sites that explain this. I'd appriciate anything at the moment.
Thanks
/Marcus
Split the operations of retrieving data from database, and building the data.
class BuilderClass {
function getClass($id, $some, $vars){
$dbResult = new db_Class::getDbRows($id, $some, $vars);
return doGetClass($dbResult);
}
function doGetClass($dbResult) {
foreach(...)
// Build something from the database values
return self;
}
}
That way, you can test doGetClass in isolation from calling the database .
As often the case, inability to easily write tests for your functions is caused by a flaw in your application design. In this case the db_Class is tightly coupled to your BuilderClass.
A proper solution would be to have a Database object in your BuilderClass using dependency injection, and mocking that injection to return a static result.
class BuilderClass
{
protected $oDatabase;
public function __construct(db_Class $oDatabase) {
$this->oDatabase = $oDataabse;
}
public function getClass($someVars) {
$this->oDatabase->getDbRows($someVars);
}
}
This way, the Database object is easily replaced with a stub.
There are many ways to do this, but since we are talking PHP, you could leverage the magic class loader function.
Simply put, if you want to mock the data access layer, you just create an object with the actual name of the data class, and the autoloader is never called.
Want to actually access the database? don't define the class and the autoloader will be called when something tries to access the database, which should then know what to do to load the class.
Mostly my autoloaders, when I use them, tend to look something like this;
function __autoload($className)
{
if(file_exists('../includes/'.$className.'.php'))
require_once('../includes/'.$className.'.php');
}
Related
I'm looking for some direction regarding the following, I'm new to OOP and getting there but think either my lack of understanding is causing me to get stuck in a rabbit hole or I'm just over thinking things too much and being anal.
basically i have a main class called "CurlRequest" which sole purpose is to perform curl requests, providing a url and params it returns me some html. This class works and functions as intended and I'm happy with that.
I use this class for a few projects but for one I then wanted to track the performance of my requests made. attempted, failed, passed etc, so i created a static class for this which manages all my counters. I place counter references like the following at different areas in my CurlRequest class.
PerformanceTracker::Increment('CurlRequest.Attempted');
PerformanceTracker::Increment('CurlRequest.Passed');
PerformanceTracker::Increment('CurlRequest.Failed');
I have around 10 or so of these with my class tracking all kinds of things during the curl request and i also use my PerformanceTracker class in other classes i made.
However like mentioned i only wanted to do this for one of my projects, so find my self in the situation of having my original CurlRequest class and an altered one with performance counters in it.
My question is, is their a way i can use the same class for any project and choose to use the PerformanceTracker class or not. The obvious way i thought of was to pass an $option argument into the class and then have if statements around all the counters, but can't help think its messy.
if ($this->options['perfCounter'] == true ) {
PerformanceTracker::Increment($this->owner . '.CurlRequest.Failed');
}
this also adds a lot of extra code to the class.
I suggest placing the if statement in a separate method
private function handlePerformanceTracker($q)
{
if ($this->options['perfCounter'] == true ) {
PerformanceTracker::Increment($q);
}
}
And call this method instead of your calls to
PerformanceTracker::Increment(...);
Also if you find that you want to track performance differently between your projects it might be useful to change your constructor to accept a callable argument, this way you externalize the actual implementation from the CurlRequest class itself.
public function __construct(..., callable performanceHandler)
Then when you instantiate your class:
$curlRequest = new CurlRequest(..., function($outcome) {
//your implementation
});
You can use inheritance and create a subclass that performs the logging before delegating to the parents methods:
class PerformanceTracker
{
static function Increment($s)
{
echo $s;
}
}
class CurlRequest
{
function get($url){
//preform curl request, save html to variable etc
//dummy vars used here so working example code
$html = 'html here';
$curlError = false;
if($curlError){
$this->error($curlError);
}
return $this->success($html);
}
protected function success($html)
{
return $html;
}
protected function error($curlError)
{
throw new Exception($curlError);
}
}
class LoggingCurlRequest extends CurlRequest
{
function get($url)
{
PerformanceTracker::Increment('CurlRequest.Attempted');
return parent::get($url);
}
function success($html)
{
PerformanceTracker::Increment('CurlRequest.Passed');
return parent::success($html);
}
function error($curlError)
{
PerformanceTracker::Increment('CurlRequest.Failed');
parent::error($curlError);
}
}
$lcr = new LoggingCurlRequest();
$lcr->get('unused in example');
As i have used dummy classes with minimal code to demo the technique the benefit might not be obvious, but in you real code, the methods in the CurlRequest class will be more complex, but the methods in the logging class will remain as two liners, with the log function and the call to the parent method.
Using this technique you can modify the parent class without effecting the derived classes (provided the method signatures dont change), can create other derived classes (how about a CachingCurlRequest) etc.
For the full benefits of OOP you should look into dependency injection and interfaces
From an OOP perspective you could use the 'Null' object pattern. This just means that the dependency used by the CurlRequest class is abstract (possibly an interface?). You would then have Two concrete implementations of PerformanceTracker: the one you have today and one that does nothing (it does not have any behavior). In this way for the one project when you instantiate the CurlRequest class it would use the concrete implementation that has behavior and for all the other projects it would use the concrete implementation with no behavior. All of the code in CurlRequest would look the same but it would have different behavior depending on which concrete implementation it was using
I am having some trouble applying Factory Pattern.
I have a class that I usually call as Product($modelNumber, $wheelCount). But in a part of legacy code that I am refactoring, I do not have $modelNumber, and only have $productID, where the link between {$modelNumber, $productID} is in the database (or in my case I can hardcode it, as I only have a select few products at the moment).
I need to be able to create my class using $productId, but how?
Using Procedural ways I would have a function that does the lookup, and I would put that function in a file, and include that file anywhere where I need to do the lookup. Thus do this:
$modelNumber = modelLookup($productId)
Product($modelNumber, $wheelCount);
But how do I do it using Object Oriented way?
Note: I have posted a more detailed situation here: https://softwareengineering.stackexchange.com/q/233518/119333 and this is where Factory pattern (and other patterns, like interfaces and function pointer passing) were suggested conceptually, but I hit a wall when trying to implement them in PHP. It kind of seems like a simple question, but I think there are several ways to do it and I am a bit lost as to how. And so I need some help.
I provided a conceptual answer to your SRP problem on Programmers Exchange but I think I can demonstrate it here.
What you basically want is some other object that will do the work to get you the model number of given product ID.
class ProductModelNumberProvider {
public function findByProductId($productId) {
// The lookup logic...
}
}
Your factory should provide a setter constructor so it can make use of this object internally to lookup the model number if needed. So basically you will end up with a ProductFactory similar to this.
class ProductFactory {
private $productModelNumberProvider;
public function __construct(ProductModelNumberProvider $productModelNumberProvider) {
$this->productModelNumberProvider = $productModelNumberProvider;
}
public function getProductByIdAndWheels($productId, $wheels) {
$modelNumber = $this->productModelNumberProvider($productId);
return $this->getProductByModelNumberAndWheels($modelNumber, $wheels);
}
public function getProductByModelNumberAndWheels($modelNumber, $wheels) {
// Do your magic here...
return $product;
}
}
EDIT
On second thought the setter is not the best approach since having a ProductModelNumberProvider instance is mandatory. That is why I moved it to have it injected through the constructor instead.
I can think of something like this:
$factory = new ProductBuilder();
$factory->buildFromProductId($productId, $wheelCount); //uses modelLookup() internally
$factory->buildFromModelNumber($modelNumber, $wheelCount); //just returns Product()
It is basically creating a class on top of the procedural function, but it does separate the logic of creating the class separately from looking up the mapping.
Through my multiple studies I have come across the factory method of setting session and database objects which I have been using while in development. What I am wondering is, putting aside personal preference (although I will soak in any opinions anyone has), does this general method work, and is it efficient (meaning, am I using it correctly)? If it is not, do you have suggestions for how to improve it?
Background
I created the code this way so as to pass a database and session object to the class upon calling the class. I wanted to be able to pass along the relevant objects/references so that they could be used.
The Call Class
This class is meant to call static functions, like so:
class CALL {
public static $_db, $_session;
public status function class1() {
$function = new class1();
$function->set_session(self::$_session);
$function->set_database(self::$_db);
return $function;
}
public status function class2() {
...
}
...
}
The _set class
class _set {
public $_db, $_session;
public function __construct() { ... }
public function set_database($_db) {
$this->_db = $_db;
}
public function set_session($_session) {
$this->_session = $_session;
}
}
Now the classes referenced.
class class1 extends _set {
function __construct() { ... }
function function1() { return "foo"; }
...
}
So, moving forward, the classes would be called using CALL::class1 or CALL::class2. After that, they can be accessed as per usual, aka:
CALL::$_db = $database->_dbObject;
CALL::$_session = $_SESSION;
$class1 = CALL::class1;
echo $class1->function1(); //prints "foo".
Read about Dependency Injection . Small suggestion from my point of view, you should never create objects like $db or $session inside other objects. You should rather inject them through constructor or setter method. It will make your code less dependant on a specific classes and it will be easier to replace all dependencies almost without refactoring (actually without one if you know hot to use interfaces).
If anyone stumbles on this, I will share with you what my solution was.
Although this exercise helped me to learn a lot, and I am sure I could take the time to create a VERY highly functional factory/Container, because this is not integral to my program and not even unique, I finally bowed to the age old wisdom of not repeating something that has already been done.
I utilized Pimple, a lightweight library that uses PHP closures to create function calls. Now, I can haave the flexibility of determining which dependency injections I want, but I also only need to inject them once. Future calls, even when they create new instances, will replicate them. While I think that, in theory, my project was workable as it was, it did indeed have the unfortunate issue of requiring you to go into the container to make changes. With Pimple I do not need to do that. So I've tossed by Container class and picked up a lightweight program from the maker of Symfony. While this may not be the best answer for everyone, it was for me. Cheers!
I was trying to find a way to execute some code to alter the results of an objects methods without actually touching the object's code. One way I came up is using a decorator:
class Decorator {
private $object;
public function __construct($object) {
if (!is_object($object)) {
throw new Exception("Not an object");
}
$this->object = $object;
}
protected function doSomething(&$val) {
$val .= "!!";
}
public function __call($name, $arguments) {
$retVal = call_user_func_array(array($this->object, $name), $arguments);
$this->doSomething($retVal);
return $retVal;
}
}
class Test extends BaseTest {
public function run() {
return "Test->run()";
}
}
$o = new Decorator(new Test());
$o->run();
That way it will work properly but it has one disadvantage which makes it unusable for me right now - it would require replacing all lines with new Test() with new Decorator(new Test()) and this is exactly what I would like to avoid - lots of meddling with the existing code. Maybe something I could do in the base class?
One does not simply overload stuff in PHP. So what you want cannot be done. But the fact that you are in trouble now is a big tell your design is flawed. Or if it is not your code design the code you have to work with (I feel your pain).
If you cannot do what you want to do it is because you have tightly coupled your code. I.e. you make use of the new keyword in classes instead of injecting them (dependency injection) into the classes / methods that need it.
Besides not being able to easily swap classes you would also have a gard time easily testing your units because of the tight coupling.
UPDATE
For completeness (for possible future readers): if the specific class would have been namespaced and you were allowed to change the namespace you could have thought about changing the namespace. However this is not really good practice, because it may screw with for example autoloaders. An example of this would be PSR-0. But considering you cannot do this either way I don't see it is possible what you want. P.S. you should not really use this "solution".
UPDATE2
It looks like there has been some overload extension at some time (way way way back), but the only thing I have found about it is some bug report. And don't count on it still working now either way. ;-) There simply is no real overloading in PHP.
Found something (a dead project which doesn't work anymore that enables class overloading): http://pecl.php.net/package/runkit
Possibly another project (also dead of course): http://pecl.php.net/package/apd
I am not a PHP programmer, but I think that AOP is what you are looking for. You can try some frameworks, for example listed in this answer.
From the Wikipedia article on the decorator pattern:
Subclass the original "Decorator" class into a "Component" class
So I think you're supposed to keep the class to be decorated private and expose only the already-decorated class.
I have a problem here, which I have been thinking about for the past few days.
In a php application to do something with a object you need to:
define it
run a function with it
like so:
(with autoloading, and a registry object)
$registry->obj = new mathClass($var1,$var2); //creates object where $var1 holds the a database object, and $var2 holds the value 1 for example
$registry->obj->calculate('value'); //fetches product rows and returns their total value.
This way at any time in the script i can simply run the calculate function (or some other function) that I defined beforehand.
Imagine a web application that has hundreds of classes that might or might not be required for this specific page load, but can only be defined at the start of the application.
The desired solution is that I simply run
$obj->calculate('price');
without creating the object, for example like this
mathclass::calculate('price');
this then autoloads the mathclass as required without having the principal overhead, the problem here is that I can no longer give the mathclass any variables at the start
($var1,$var2).
What I want is to be able to pseudo-create the object without any autoloading of the class happening, as to not add the overhead, but that the object creates itself with the variables but only when I actually need to do something with it.
I mean does php really expect me to define each and every class at the start so that I can later use them?
is this Lazy-loading? Eager loading?
I might be explaining this badly so please point me in the right direction.
Edit 2015: Simple pseudocode example solution:
class Service {
private $cb, $instance;
public function __construct($cb){
$this->cb = $cb;
}
public function __invoke() {
if(!$this->instance){
$this->instance = call_user_func($this->cb);
}
return $this->instance;
}
}
// setup autoloading
set_include_path(__DIR__.'/vendor'. PATH_SEPARATOR .get_include_path()); // optional
spl_autoload_register(function($c){
include preg_replace('#\\\|_(?!.+\\\)#','/',$c).'.php';
});
// simple dependency injection
$service['db'] = new Service(function(){
return new Database('sqlite::filename.sqlite');
});
$service['config'] = function() use(&$service){
return new Config($service['db']());
};
$service['math'] = function() use(&$service){
return new Math($service['config']());
};
// usage
$service['math']()->calculate('price');
Use a Dependency Injection Framework. It lets you configure your classes from config files and when you need a class you simply call it through the service builder.
You can use a lazy loading factory, i.e.
class Registry
{
private $registeredClasses;
private $loadedClasses;
private $objects;
public function RegisterClass($className, array $parameters)
{
// ... store class ...
}
private function Load($className)
{
// Load the class via some sort of autoloader
}
private function CreateInstance($className)
{
$parameters = $this->GetParametersFor($className);
$this->CreateNewInstanceWithParameters($className, $parameters);
}
public function GetObject($className)
{
if (!$this->IsAvailable($className))
{
$this->Load($className);
$this->CreateInstance($className);
}
return $this->GetInstanceOf($className);
}
}
Later in your code you use it like this:
$registry = new Registry();
$registry->RegisterClass("math", array("var1" => $var1, "var2" => $var2));
...
$registry->GetObject("math")->calculate($x1, $x2);
...
Ofc you need to add the parts i was too lazy to add, i.e. the autoloading.
if you use the autoload functionality it will only load the math class when you instantiate it, 1 option is to instantiate it when you need it, another option is to use some kind of wrapper class that will include and call the class.
What you can use is Static classes in PHP. Although this is something you might consider not doing for high-traffic websites.
Declare a class like so:
class Something
{
private static $var = "something";
public static function PrintVar()
{
echo self::$var;
}
}
Now you can include this class and execute the code anywhere you like without initializing the object.
Like so:
Something::PrintVar();
prints
something
Good luck!
Part of the reason why class objects require defining using new() is because they consume memory. Normally PHP will perform memory cleanup at the end of script if you havent done so, but usually in a constructor/destructor object-oriented environment you would want to unset() that class object to free up memory. Earlier versions of PHP (before php4) had issues with memory leaks due to these reasons.
If you want to avoid the whole initialization process you may just want to try a simple include library, such as this:
<?
if (!function_exists("calculate"))
{
function calculate($var1={default},$var2={default})
{
...routine...
}
}
?>
And then you do not have to deal with the whole pain of defining a full class for a simple routine.