php file having wrapper class instead of arguments in file's functions - php

I've the following files:
`index.php`
`settings.php`
`functions.php`
settings.php:
....
$object = new SomePhpClass();
....
index.php:
require_once('settings.php');
require_once('functions.php');
....
some_function($object);
some_other_function($object);
....
functions.php:
function some_function(SomePhpClass $object){
//Do something with $object
}
function some_other_function(SomePhpClass $object){
//Do some here
}
In my above code, I've passed the $object in the function. The above code works as of now. I want the functions.php to accept a wrapper class to SomePhpClass instead of directly passing the $object. I'm a newbie here and don't know how to go about writing the wrapper class to achieve such thing.

Wrapper classes can be used for a lot of different reasons. Most of the time you use them to either hide the functionality of existing classes of yours so that the consumer only sees a limited interface (facade) or you can also use them to augment the functionality of an existing class or its method (decorator). Sometimes they are used as an adapter between different interfaces.
The basic idea of a wrapper class is that you define a class which contains the object you are wrapping (usually as private property) and defines the methods you want to make accessible. If your intention is to hide certain methods of your original object, the methods on your wrapper class will be a subset of your wrapped object's methods and will simply forward the call to the wrapped object and return whatever it returned. If you want to extend the object's functionality, you can also define new methods on your wrapper which do whatever magic you want them to do on your object.
A typical implementation could look something like this:
class SomePhpWrapper {
/**
* The wrapped object
*/
private $wrapped;
/**
* Wrapping constructor
*/
public function __construct(SomePhpClass $object) {
$this->wrapped = $object;
}
/**
* A method of the wrapped object we would like to explose on the wrapper
*/
public function someMethod($someArgument) {
return $this->wrapped->someMethod($someArgument);
}
/**
* A decorated method which calls the wrapper class's method but also does something else
*/
public function query($params) {
$returnValue = $this->wrapper->query($params);
doSomethingFunky();
return $returnValue;
}
/**
* Another exposed method
*/
public function ping() {
return $this->wrapped->ping()
}
/**
* A decorator method that does not exist on the wrapped object but would be useful
*/
public function somethingComplicated() {
$this->wrapped->query(this);
$this->wrapped->query(that);
}
}
This wrapper hides some methods of your original class and also add a new method called somethingComplicated().
This wrapper, however, is not a subclass of your original class. When you write functions that use this wrapper class, they should not expect SomePhpClass, they should expect SomePhpWrapper instead. In your case:
function some_function(SomePhpWrapper $object) {
$object->ping(); // works
$object->somethingComplicated(); // works
$object->getDebug(); //fails, as getDebug() is not exposed by the wrapper
}
To use this wrapper you could go like this:
$object = new SomePhpClass();
$wrapper = new SomePhpWrapper($object);
some_function($wrapper);

Related

Passing a private property between objects of different type

I have the following objects that I would like make them cooperate between themselves. The user could create each object separated from the others and at different time. The final usage is that the user links all the objects together to compose the final one.
Invoice.php
<?php
class Invoice
{
private $header;
private $xml;
public function __construct()
{
// code that initializes $this XML tree (root)
}
public function setInvoiceHeader($invoiceHeader)
{
/* code that should merge $this->xml with the one from the $invoiceHeader param
but I can't access it here because of private visibility and I would like to avoid
the public visibility */
}
public function writeXMLDocument()
{
// code that returns the XML document
}
}
?>
InvoiceHeader.php
<?php
class InvoiceHeader
{
private $xml;
public function __construct()
{
// code that initializes $this XML tree
}
public function setTransmissionData($transmissionData)
{
/* code that should merge $this->xml with the one from the $transmissionData param
but I can't access it here because of private visibility and I would like to avoid
the public visibility */
}
}
?>
TransmissionData.php
<?php
class TransmissionData
{
private $xml;
private $transmissionIdNode;
public function __construct()
{
// code that initializes $this XML tree
}
public function setTransmissionId($idCountry, $idCode)
{
// code that creates the XML node with the params
}
}
?>
I can't find a way to pass the private $xml between the objects.
I would like to avoid using the public visibility because I don't want that the user can access the low-level implementation.
I would like to avoid using the inheritance and protected visibility because I think that these objects are not so much related (InvoiceHeader is not an Invoice and TransmissionData is not an InvoiceHeader); furthermore the only thing that they would have inherit is a field.. it is like a waste to my ears.
I would like to treat them more like some components, assuming it is possible.
You could have InvoiceHeader hold a TransmissionData object (set by your current set method), and have TransmissionData object expose a method to get the generated XML so that you don't need to expose the raw properties, only the resultant XML block?
Similarly the Invoice could hold an Invoice header object property, and InvoiceHeader exposes another method to get the required XML, again keeping property editing within the core class and only exposing the data in the consumable format?
If multiple sections of XML are required at any point to put into various places in the final result, you could expose a number of methods for each required block.
I'll not try to type out php code here - I'm rusty!

How to fix mockery mock object throwing BadMethodCallException?

In a silex application I have a KafkaAPiClient class which definitely has the public method postMessages.
<?php
namespace Kopernikus\KafkaWriter;
use Kopernikus\KafkaWriter\Model\AbstractMessage;
/**
* KafkaApiClient.
**/
class KafkaApiClient
{
/**
* #param AbstractMessage[] $msg
*/
public function postMessages(array $messages)
{
foreach ($messages as $message) {
$this->postMessage($message);
}
}
public function postMessage(AbstractMessage $msg)
{
...
}
}
I can call KafkaAPiClient::postMessages just fine, yet when mocking the class in a test:
<?php
namespace unit\Request;
use Kopernikus\KafkaWriter\KafkaApiClient;
/**
* MockeryMethodsNotBeingCallableTest
**/
class MockeryMethodsNotBeingCallableTest extends \PHPUnit_Framework_TestCase
{
public function testMockMethodIsCallable()
{
$leMock = \Mockery::mock(KafkaApiClient::class);
$leMock->postMessages([]);
}
}
I am getting:
1) unit\Request\MockeryMethodsNotBeingCallableTest::testMockMethodIsCallable
BadMethodCallException: Method Mockery_11_Kopernikus_KafkaWriter_KafkaApiClient::postMessages() does not exist on this mock object
~/le-project/tests/unit/Request/MockeryMethodsNotBeingCallableTest.php:14
I am confused, I was expecting for the mock to not do anything yet allow the methods to be called so that I later could add my expectations on it.
Though I have found a solution, I am still wondering if it is possible to mock all the methods by default, and later check if certain ones have been called.
There exists shouldIgnoreMissing method on the mock object. Calling that does exactly what it says on the tin, that is: ignoring calls to not yet defined methods, resulting in a mock that does nothing:
$leMock = \Mockery::mock(KafkaApiClient::class);
$leMock->shouldIgnoreMissing()
$leMock->postMessages([]);
And by nothing, it means nothing. I got into an other error for my queue when I instantiated the mock that way, as methods will return null by default and their return value has to be explicitly stated.
$msg = new Message('dummy-message');
$this->kafkaQueue
->shouldIgnoreMissing()
->shouldReceive('getMessages')->andReturn([$msg]);
Any call to getMessages will now return exactly the array [$msg].
Alternatively, one can be very explicit about what methods are called with Mockery, by adding shouldReceive:
public function testMockMethodIsCallable()
{
$leMock = \Mockery::mock(KafkaApiClient::class);
$leMock->shouldReceive('postMessages');
$leMock->postMessages([]);
}

Extend existing class method

Can I somehow extend existing class method from plugin? Or can I monitor output every time method get called?
There is
class greatPlugin{
...
public function someProcess($vars){
/* The magic */
return $stringFromProcess;
}
...
}
greatPlugin is called by hook inside WordPress before theme is loaded, but I need access (preferably) array of outputs generated by someProcess method. For example
$greatSubOutput = array('string1', 'string2');
or just $greatSubOutput = null; if method was not called.
The greatPlugin class is too complex to rebuild it's great work done by original dev. If I could add just some log2array feature to that function...
You can always extend the entire class, and then extend the method like so:
class loggingGreatPlugin extends greatPlugin
{
public function someProcess($vars) {
$output = parent::someProcess($vars);
$logger = new LogMe();
$logger->log(LogLevel::INFO, $output);
return $output;
}
}

How can I using Class::Function(params) without static

* Sorry, I am learning English now and my English is still not so good. Please understand my situation.
As far as I know, Static is required to use like Class::Function(params);
Like this one.
class Foo {
static function Bar($msg){
echo $msg;
}
}
There is one file in XE(is CMS developed in Korea).
(XE Official Site : http://www.xpressengine.com/?l=en)
Of course, This is a summary of real file
<?php
/**
* Manages Context such as request arguments/environment variables
* It has dual method structure, easy-to use methods which can be called as self::methodname(),and methods called with static object.
*/
class Context
{
/**
* codes after <body>
* #var string
*/
public $body_header = NULL;
/**
* returns static context object (Singleton). It's to use Context without declaration of an object
*
* #return object Instance
*/
function &getInstance()
{
static $theInstance = null;
if(!$theInstance)
{
$theInstance = new Context();
}
return $theInstance;
}
/**
* Add html code after <body>
*
* #param string $header Add html code after <body>
*/
function addBodyHeader($header)
{
is_a($this, 'Context') ? $self = $this : $self = self::getInstance();
$self->body_header .= "\n" . $header;
}
}
This is the comment at the top of this file.
It has dual method structure, easy-to use methods which can be called
as self::methodname(),and methods called with static object.
In this comment, It can use Class::Function() and I have been using in XE.
But it don't tell how they make. How can I make like it?
Edit1 :
The file's name is Context.class.php and It is included in other files.
<?php
require(_XE_PATH_ . 'classes/context/Context.class.php');
Context::addBodyHeader("Some Codes");
?>
In this comment, It can use Class::Function() and I have been using in
XE. But it don't tell how they make. How can I make like it?
The :: is called the scope resolution operator.
They make it as follows:
class MyClass {
public static function saySomething() {
echo 'hello';
}
public function sayHello() {
echo 'hello';
}
public function helloSay() {
self::sayHello();
}
}
MyClass::saySomething();
MyClass::sayHello();
MyClass::helloSay();
They all output: hello
Well in this case they use self, which doesn't need the static, you can compare self:: to $this->, just that self:: also works for static functions.
Maybe the manual helps you
Not sure if this is what you are trying to do, but you can declare "static" in php public static function methodName() and then call the function with Class::Method() You can also check out this for more data on static.
EDIT:
This is from php.net:
The pseudo-variable $this is available when a method is called from
within an object context. $this is a reference to the calling object
(usually the object to which the method belongs, but possibly another
object, if the method is called statically from the context of a
secondary object).
So basically you can do this (call class method static way).

Static variable assignment in descendent bubbles up to parent?

I've run into a problem and I'm not sure if this is just normal behaviour or if I wrote something wrong. I have a method in my base class that applies a global filter to a given class by way of creating a proxy for all new instances of that particular class. The way I planned to go about it is as follows:
Attach static $global_filter (the proxy) to the class I want to be filtered, which extends the base class object
Via my loading mechanism, return the proxy instead of the actual class upon new instantiations (which will mask method calls and apply filters accordingly)
However, I am getting stuck in step 1 and it seems that when I try to assign static $global_filter to the descendent class I want filtered, my base class object also gets the same assignment, which breaks everything else that extends from it.
Please see below for relevant code:
class object {
public static $global_filter;
public function _filterGlobal($class, $method, $callback) {
if ( !is_object($class::$global_filter) ) {
$class::$global_filter = new filterable(null);
# Replace the object being called with the new proxy.
}
var_dump($class);
var_dump($class::$global_filter); // `filterable`
var_dump(\core\blueprint\object::$global_filter); // Returns same as line above
die();
return $class::$global_filter->_add($method, $callback);
}
}
Both $class::$global_filter and \core\blueprint\object::$global_filter (the base class) are returning same instance. Whereas I expected object::$global_filter to be null.
I'm not using late static binding in order to preserve consistency (both single-object filters and global filters are called much in the same way non-statically).
This question seems relevant
Any help will be much appreciated :)
Edit, full example
This would be a concrete class, which extends model which extends object
<?php
use core\blueprint\model;
class modelMock extends model {
protected $schema = array();
public function method($test) {
return $test;
}
}
This would be another object (e.g a controller), which extends object aswell. It applies a filter to all new instances of model
<?php
use core\blueprint\object;
class objectMock extends object {
public function applyFilters() {
$this->_filterGlobal('core\blueprint\model', 'method', function($self, $chain) {
$chain->params[0] = 'new param'; // adjust the paramters
return $chain->next();
});
}
}
when I try to assign static $global_filter to the descendent class I want filtered, my base class object also gets the same assignment
Yes, indeed this happens. A static property in essence is a global variable, constrained within the class's namespace. Running into problems with global variables is often an indication you're not using the best solution.
To solve your problem, you could make the filter a (non-static) property:
$class->$filter = new Whatever();
But as always, there's more roads that lead to Rome, and I would advise you to look for alterative ways to do it.
I don't know if this is a help for you:
class a {
public static $type;
public static function setType($class, $newType) {
$class::$type = $newType;
var_dump($class::$type);
}
}
class b {
public static $type = 'myType';
}
var_dump(b::$type);
a::setType('b', 'yourType');
var_dump(a::$type);
May be you have not defined the static property to the concrete class.
Thanks everyone for you help, I spent some time on it this morning and managed to solve my problem. It's a bit of a workaround but here's how it goes:
public function _filterGlobal($class, $method, $callback) {
if ( !is_object($class::$global_filter[$class]) ) {
$class::$global_filter[$class] = new filterable(null);
# Replace the object being called with the new proxy.
}
return $class::$global_filter[$class]->_add($method, $callback);
}
So basically in order to get unique static variables working in child classes without having to explicitly define them, you can use an array that stores the child's class name as a key and then access these variables via a getter.

Categories