PHP Chain with Parent Function - php

I'm wanting to chain a method with the parent function of itself.
Example:
class Query
{
protected $limit;
/**
* Returns some third object that isn't in this family.
* This object represents the results, and also has
* a first function that gets called in a chain.
*/
public function get()
{
// Do Stuff
return new /* ... */;
}
public function take($amount)
{
$this->limit = $amount;
return $this;
}
}
class ChildQuery extends Query
{
protected $singular = false;
public function get()
{
if($this->singular)
return $this->take(1)->parent::get()->first();
return parent::get()
}
public function singular()
{
$this->singular = true;
return $this;
}
}
This obviously isn't the full set of functions, nor does it work, but you get the idea. I'd like ChildQuery::get to be able to call Query::get in a chain.
Right now, I have to do this:
public function get()
{
$this->take(1);
parent::get()->first();
}
Which is not appealing to me. Any ideas?
I'm running PHP 7, if it matters.
My end result would look something like this:
$query->singular()->get(); // ($query is a ChildQuery)

It is just not possible to call a parent method by the public interface of an object (even if it is the same class/object like the current context). Please have also a look at https://stackoverflow.com/a/11828729/2833639.
In my opinion your solution is the right way to go.
Off Topic: I recommend to read https://ocramius.github.io/blog/fluent-interfaces-are-evil/ to evaluate whether a fluid interface is good for your use case.

Related

Simulate a generic class in PHP

I'm trying to implement a Results class that processes queries. So, simply put, you would have functions like this:
function all();
function first();
function paginate(int $perPage, int $pageNo = 1);
This works pretty well, the problem being that the IDE has no possible way of knowing the return type when this same results class is being used in multiple different query classes. Example:
UserQuery->results()->all() will return an array of User entities.
UserQuery->results()->first() will return a single User entity.
In some languages, you have generics, which means I could just use Results<User> in the UserQuery class and then my Results class could return T[] and T respectively.
One idea I had was to pass an empty entity as the constructor to the Results class and then try to use that property as the return type, but I couldn't figure this out. Is there any workaround to this? The main problem I'm trying to solve is IDE autocompletion and analysis, so a pure phpDoc solution is perfectly fine for my use case.
The only other workaround I can come up with is having to write a separate Results class for each entity type, which would prove to be exhausting.
I don't think there's a way to do exactly what you described, but in similar cases I would suggest using a proxy class for each Results type and document proper return types using phpDocumentor's #method. This solution has added value of having a great place for any type specific Results modifications and expansions. Here's an example:
abstract class Results
{
function all(): array
{
}
function first()
{
}
function paginate(int $perPage, int $pageNo = 1): array
{
}
}
class User { }
/**
* #method User[] all()
* #method User first()
* #method User[] paginate(int $perPage, int $pageNo = 1)
*/
class UserResults extends Results { }
class UserQuery
{
/**
* #var UserResults
*/
private $results;
public function __construct()
{
$this->results = new UserResults();
}
public function results(): UserResults
{
return $this->results;
}
}
$userQuery = new UserQuery();
$test = $userQuery->results()->all();

Coupled method PHP OO

I'm picking up a bit to create a method for database as shown in the example below:
$db = new Query();
$db->select('field')
->from('table')
->where('condition')
->etc. etc.
Ie a method with another to return a complete sql (SELECT FROM table WHERE condition fields etc etc).
My question is: How to create a class?
Grateful.
Basically you just return $this at the end of each method you want to be chain-able.
Using your sample API, the implementation would look something like this:
<?php
class Query {
public function select($arg) {
// do stuff
return $this;
}
public function from($arg) {
// do stuff
return $this;
}
public function where($arg) {
// do stuff
return $this;
}
}

Attempt to assign property of non-object error

I am getting this error and i can't see what i am doing wrong. I have done the same thing with other objects from other classes which are built in the exact same way and i can't see why i am getting this error now.
The code in which i create the object is this one:
$consulta2 = "SELECT * FROM TiposDireccion WHERE Cliente_CIF='$cif' and Direccion_Direccion='$direccion' and Direccion_CP=$cp ";
echo($consulta2."</br>");
if ($resultado2 = $conexion->query($consulta2)){
while($fila2 = $resultado2->fetch_object()){
$tipodireccion78=$fila2->TipoDireccion_Tipo;
//we see here that the select is returning a correct string with a correct value
echo($tipodireccion78);
//we try to instantiate and it fails =(
$unTipoDireccion=TipoDireccion::constructor1($tipodireccion78);
This is the class TipoDireccion:
<?php
class TipoDireccion{
private $tipo;
private $descripcion;
//Construct auxiliar
function __construct() {
}
//Constructor 1 : completo
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->tipo = $tipo;
return $tipoDireccion;
}
function ponTipo($tipo) {
$this->tipo = $tipo;
}
function devuelveTipo() {
return $this->tipo;
}
function ponDescripcion($descripcion) {
$this->descripcion = $descripcion;
}
function devuelveDescripcion() {
return $this->descripcion;
}
}
?>
Thank you a lot in advance!
Don't know if this is still relevant to you, but in case anyone else comes on here for an answer. The problem is in this function:
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->tipo = $tipo;
return $tipoDireccion;
}
Because in the class definition, you define private $tipo; and then you try and assign $tipoDireccion->tipo to what was passed through the function. However, you aren't trying to access that variable through the scope of the class, you are trying to assign it from the 'public' scope as far as the class is concerned.
The fix for this has two options, the first one would be to change private $tipo; to public $tipo;. But that isn't a good solution as you have an assignment function for it.
Instead, use your functions that you made, which would make the function look like:
function constructor1($tipo) {
$tipoDireccion = new TipoDireccion();
$tipoDireccion->ponTipo($tipo);
return $tipoDireccion;
}
That's how you need to access it from the public scope, which you are doing after you initiate a new one.
function constructor1($tipo) {}
should be
static function constructor1($tipo) {}

Php Calling the functions of same class one after another

I want to write something like (laravel uses):
View::make('FooBarView')->with('foo', $foo)
->with('bar', $bar);
My knowledge and imagination made me to use new self instances. But I don't think that this is the best idea around and I could not handle it.
Google couldn't help me because of my bad keywords I think. I don't want to make you write code for me for sure but what is the name of this design pattern or whatever?
In laravel's source, with function uses
return $this;
But how to use it after make?
By the way, in this example; with method helps you to set variables for view's render.
To call what the function returns, the function will have to return something that is possible to call.
In this case, you could for example return "this":
class View {
/**
* #returns View
*/
public static function make($foo) {
/* do stuff, return new View instance */
return new View();
}
/**
* #returns View
*/
public function with($foo, $bar){
/* do stuff */
return $this;
}
}
That way, whenever you call with you will get the class instance back, which in turn will be callable:
View::make("foo")->with("foo")->with("bar");
// Will be same as:
$v = View::make("foo");
$v = $v->with("foo");
$v = $v->with("bar");

PHPUnit Test How Many Times A Function Is Called

I'm working on a test in phpunit and I'm running into an issue. I have a public function on my class that I am trying to test. Depending on the parameters passed in to the method, a protected function also in my test class will be called one or two times. I currently have a test in place to check that the return data is correct, but I would also like to make sure the protected method is being called the correct number of times.
I know that a mock object will allow me to count the number of times a function is called, but it will also override the value returned by the protected function. I tried using a mock object with no "will" section, but it would just return null, not the actual value for the protected method.
ExampleClass
public function do_stuff($runTwice){
$results = do_cool_stuff();
if($runTwice){
$results = 2 * do_cool_stuff();
}
return $results;
}
protected function do_cool_stuff()
{
return 2;
}
In my test, I want to check whether do_cool_stuff() was called once or twice, but I still want the return values of both functions to be the same so I can test those as well in my unit test.
tl;dr
I want to count the number of times a protected method in my test object is called (like you can do with a mock object) but I still want all the methods in my test method to return their normal values (not like a mock object).
Alternatively, revert back to rolling your own testable stand-in. The following aint pretty, but you get the idea:
class ExampleClass {
public function do_stuff($runTwice) {
$results = $this->do_cool_stuff();
if ($runTwice) {
$results = 2 * $this->do_cool_stuff();
}
return $results;
}
protected function do_cool_stuff() {
return 2;
}
}
class TestableExampleClass extends ExampleClass {
/** Stores how many times the do_cool_stuff method is called */
protected $callCount;
function __construct() {
$this->callCount = 0;
}
function getCallCount() {
return $this->callCount;
}
/** Increment the call counter, and then use the base class's functionality */
protected function do_cool_stuff() {
$this->callCount++;
return parent::do_cool_stuff();
}
}
class ExampleClassTest extends PHPUnit_Framework_TestCase {
public function test_do_stuff() {
$example = new ExampleClass();
$this->assertEquals(2, $example->do_stuff(false));
$this->assertEquals(4, $example->do_stuff(true));
}
public function test_do_cool_stuff_is_called_correctly() {
// Try it out the first way
$firstExample = new TestableExampleClass();
$this->assertEquals(0, $firstExample->getCallCount());
$firstExample->do_stuff(false);
$this->assertEquals(1, $firstExample->getCallCount());
// Now test the other code path
$secondExample = new TestableExampleClass();
$this->assertEquals(0, $secondExample->getCallCount());
$secondExample->do_stuff(true);
$this->assertEquals(2, $secondExample->getCallCount());
}
}
I wonder though whether counting the number of times a protected method has been called is really a good test. It's coupling your test to the implementation pretty hard. Does it really matter whether it is called twice, or are you more interested in the interactions with other objects? Or maybe this is pointing towards do_cool_stuff needing a refactor into two separate methods:
class ExampleClass {
public function do_stuff($runTwice) {
if ($runTwice) {
return $this->do_cool_stuff_twice();
} else {
return $this->do_cool_stuff_once();
}
}
//...
}
Try setting a global variable prior to utilizing the class.
$IAmDeclaredOutsideOfTheFunction;
then use it to store the count and simply check it after your functions and classes have been called.

Categories