How can a function call itself in PHP? - php

I am new with Laravel and PHP so I decide to see the core code and try to read it a little, but when I reached this part, I am confused! how does this function works? $this->getAlias($this->aliases[$abstract]); can a function call itself? wouldn't it be looping?
protected function getAlias($abstract)
{
if (! isset($this->aliases[$abstract])) {
return $abstract;
}
return $this->getAlias($this->aliases[$abstract]);
}
thank you

You may want to read about recursive functions.
A recursive function is a function that calls itself
This function takes some argument and checks if it has an alias. If it does, it calls itself again and checks if found alias has an alias etc.

These are called recursive functions... Which means, a function can call itself until the final condition for the expected output is reached.
A simple example for this would be... Multiplication of 2 until the sum reaches 100.
public function multiplication($a, $sum = 0, $times = 0) {
if($sum == 100) {
return $times;
}
$sum += $a;
$times++;
return multiplication($a, $sum, $times);
}
echo multiplication(2);
Output will be
50
In the function written in the question, it is trying to check if all the abstract value passed as param is set for that current class or not.
Hope you are now clear of the concept. :)

Related

Specific php functionality

My team lead some time ago asked this question, which I didn't understood:
Implement function calc()
Please, implement function calc so code below works:
$sum = function($a, $b) { return $a + $b; };
calc(5)(3)(2)($sum); // 10
calc(1)(2)($sum); // 3
calc(2)(3)('pow'); // 8
So, can someone explain me what is it, and maybe some link on this functionality
The following will satisfy your example use:
<?php
function calc($input)
{
static $args = [];
if(is_callable($input)) {
$carry = array_shift($args);
$result = array_reduce($args, $input, $carry);
$args = []; // Clear the arguments.
return $result;
} else {
$args[] = $input; // Add arguments to the stack.
return __FUNCTION__;
}
}
$sum = function($a, $b) {
return $a + $b;
};
echo
calc(5)(3)(2)($sum), "\n",
calc(1)(2)($sum), "\n",
calc(2)(3)('pow'), "\n",
calc(5)(2)(2)('pow');
Output:
10
3
8
625
Explanation:
When calc is called with a single argument (that is not a callable), the input is pushed to an array and the name of the function, here 'calc', is returned.
calc(2)(3) will add 2 to the static array (this will persist between subsequent function calls), and return the function name. So this becomes calc(3), where the previous call has the side effect of storing 2 in $args.
If the argument passed is a callable. array_reduce will pass pairs of arguments from $args left to right to the callable, seeding subsequent calls with the result of each iteration.
array_reduce([1,2,3], 'pow', $initial) is similar to the following:
$result = pow($initial, 1);
$result = pow($result, 2);
$result = pow($result, 3);
However we need to use array_shift to remove the first item from the $args array as a seed for the first iteration of the pow call:
So that becomes array_reduce([2,3], 'pow', 1).
We then clear the argument list, otherwise subsequent calls to calc will use these arguments again, and the result of the array_reduce is returned.
You could have it as a calc function that takes a value and:
if it's a not a function, adds it to a buffer array, then return the function itself,
if it's a function, calls that function subsequently on every value of that buffer.
So if we take calc(6)(3)($sum):
calc(6) call will add 6 to the buffer array then return the calc function,
(3) will therefore pass 3 as a param to that same calc function that was just returned, therefore adding 3 to the buffer and returning the calc
function again,
finally, ($sum) will generate a call to that $sum function, passing it every value from the buffer (therefore, 3 then 6), reducing it into the final result.
Code:
function calc($value_or_function, array $buffer = [])
{
// If the argument is callable (a function), check that the buffer has
// at least one value and call this function subsequently on each value,
// reducing it into a final value
if (is_callable($value_or_function)) {
if (count($buffer) === 0) {
throw new \InvalidArgumentException('Not enough parameters.');
}
return array_reduce(array_slice($buffer, 1), $value_or_function, $buffer[0]);
}
// Otherwise (not a callable arg), add it to the buffer and return the
// function itself so that its result can be chain-called
return static function ($otherValue) use ($buffer, $value_or_function) {
return calc($otherValue, array_merge($buffer, [$value_or_function]));
};
}
// Example usage
$sum = function ($a, $b) { return $a + $b; };
echo calc(5)(4)(3)($sum), PHP_EOL;
echo calc(5)(2)(2)('pow');
Additional notes:
this is a decent exercise but probably a bad idea to have in a real codebase, this is quite unintuitive, the function does too many things, doesn't have strictly typed params, etc.,
those inline comments are a bit much for real code (they're that detailed for explanation purposes).
Demo: https://3v4l.org/AoKJO

how to execute remaining code after calling another method within same controller in laravel?

I'm using laravel 5.8. There are two functions in my laravel controller. After calling one function into another remaining code does not execute. Is there a way to execute the remaining body of function? I have tried calling function without return statement function is not called.
public function a(){
return "function a";
}
public function b(){
return $this->a();
// after the above statement remaining code does not execute
echo "function b";
}
The return keyword gives the answer to your confusion. Return means execute this line and exit the function. Of course it will not continue with the rest of the code.
It depends what you want to do with the result of the first function, but if you want the result you can store it in a variable and use it for other calculation, for example this will work:
public function b(){
$result = $this->a();
echo "function b and result of a: " . $result;
}
--- EDIT
After your comment below, the best way to check if user is logged in or not is not to have a separate function for that but you can achieve that using a middleware. So instead of having separate function, on your route you can define it as this:
Route::get('endpoint', 'YourController#b')->middleware('auth');
This middleware will redirect the user to the login page unless he is logged in.
If none of the above is considered as solution for your case, then I found a duplicate question as your original one here.
It's quite normal reaction for PHP
Please check manual of "return" from here:
https://php.net/manual/en/function.return.php
It says "... If called from within a function, the return statement immediately ends execution of the current function, and returns its argument as the value of the function call. ..."
I hope this helps.
You want to use the data returned from function a in function b ?
public function a()
{
$collection = DB::table('foo')->get();
return $collection;
}
public function b()
{
$data = $this->a();
// Do something
dd( $data );
}

Sum of all the columns of a rows in Laravel

How can I find out the sum of certain columns of a row in MySQL using Laravel?
I know ->sum('something'); gives you the sum of a column. But what about a row?
Is there any method to do so in Laravel?
Currently I'm adding each column values manually and getting the sum.
There is no built-in way to do this, but you can write a function yourself. Well, actually, I did that already for you! ;)
You have two options. The boring one, a function that just returns a predefined sum:
public function getSum(){
return $this->value1 + $this->value2; // and so on
}
Or a generic function that you can place inside a BaseModel and use in every class and with every attributes you want:
public function getAttributeSum(){
$sum = 0;
foreach(func_get_args() as $attribute){
$sum += $this->getAttribute($attribute);
}
return $sum;
}
And you call it like this:
$model->getAttributeSum('value1', 'value2');
Just create a model function and pass all the variables to it and do the calculation there. Then return the total and print wherever you want it.
{{Classmodel::total($yourvariablearray)}}
In the Classmodel.php you will have something like:
public static function total($variablearray){
return $total = $variablearray->columnone + $variablearray->columntwo;
}
This should work.
How about this
return \DB::table('table_name')->sum('column_to_be_calculated');
Works for laravel 5 .

Multiple return from a class function

I am learning php OOP. While writing a class I am getting a logical problem that the function is not returning more than one value and I am just getting default value as output.
When I pass two variables in a function setproperty() and call back getproperty(), it returns only author's name. Here is the code:
class library{
public $BookName="PHP OOP Programming";
public $author="Faisal";
public function setproperty($a_name,$b_name){
$this->author=$a_name;
//$this->BookName=$b_name;
}
public function getproperty(){
return $this->author."<br />";
//return $this->BookName."<br />";
}
}
$obj=new library;
//var_dump($obj);
echo $obj->getproperty();
$obj->setproperty("naseer","SQL");
echo $obj->getproperty();
And I'm getting the output:
Faisal
naseer
Whereas the output I wanted is author's name along with books, much like:
Faisal
PHP OOP Programming
naseer
SQL
You cannot return multiple times in a function.
If you need to return more than one value you can do something like:
return array('author'=>$this->author, 'bookName'=>$this->bookName);
And use it like this:
$res = $obj->getproperty();
echo "Author is ".$res['author'];
echo "Book is ".$res['bookName'];
You may want to change this depending on what the method is for/ how it will be used.
A return statement is the end of any function. That's why a function is said "to have returned" when it's done doing whatever it needs to do. This isn't unique to OO, but to functions in all programming languages.
What you want to do is:
return $this->author.'<br/>'.$this->bookName.'<br/>';
Here, I'm concatenating all values into one string constant, and return that. This way, I have a single return value, and a single return statement with the desired output.
Like I said, even non-methods (regular functions) can't return more than 1 value - nor can they return less than 1 value:
function aFunction()
{
echo '123';
}
Though lacking an explicit return:
$foo = 'not null';
$foo = aFunction();
var_dump($foo);//null!
the function clearly does return null, just like in C, a function that needn't return any value, returns void, or a JavaScript function returns undefined. The same applies to methods: they return null, implicitly or a single explicit return value.
You could write code like this, too:
function sillyFunction($someArgument = 1)
{
return true;
if ($someArgument < 0)
{
return false;
}
if ($someArgument === 0)
{
return null;
}
return $someArgument%2;
}
This function starts with a return true; statement. Any code that follows will never be reached, and thus never get executed, because this function has to return something to the caller, who then takes over again. You can't go back to the function and continue what you were doing there. A function is a one-go thing.
Workarounds: Thankfully, objects and arrays are regarded as a single value, so they can be returned from a function, and can contain multiple values. So that's the most common way to somehow get a function to return multiple values. The only, minor downside is that, once the function has returned, you have but a single access point for all these values: the variable to which you assigned the return value:
function foo()
{
return array('foo' => range(1,100), 'bar' => range('A','Z'));
}
$foo = foo();
echo $foo['foo'][1], ' => ', $foo['bar'][1];//echoes 2 => B
In some really rare cases (in the past 10 years, I've needed this ~5 times) you can sort-of return several values using references:
function changeArrayAndReturn(array &$arrayRef)
{
array_push($arrayRef, 'I was added in the function');//alters array
return count($arrayRef);//AND returns int
}
$foo = array();
echo changeArrayAndReturn($foo);//echoes 1
$foo[] = 'I was added outside of the function';
echo changeArrayAndReturn($foo);//echoes 3
var_dump($foo);
//array(I was added in the function, I was added outside of the function, I was added in the function)
But that's dangerous and hard to maintain, so stay away, unless you really can't do it any other way
A function stops when it encounters the first return. So it never gets to the line you commented out (even when it is not a comment).
public function getproperty()
{
return $this->author."<br />".$this->BookName."<br />";
}
That way you display both values with a single return. You could also return an array if you preferred.

Method chaining without final method

I came across plenty of examples of method chaining in PHP, but couldn't find anything about this one, so I'm asking for help you guys;)
My problem is - can I in some way find out if the method in chain is the last one? In most cases people are using some sort of final method (execute, send,..) to tell when the chain ends and return the corresponding result. But I wonder if there is some hidden magic method or technique than can check all the methods in chain and detect if there is no next method?
Without final method it works fine for strings (in the very simple example), but not if I want to return array.
Here is my snippet :
class Chain {
private $strArray;
function __call($name, $args) {
$this->strArray[] = $args[0];
return $this;
}
function __toString() {
return implode('-', $this->strArray);
}
}
// example 1
$c = new Chain();
$x = $c->foo('hi')->bar('stack'); // need array('hi', 'stack')
// example 2
$c = new Chain();
$x = $c->foo('hi')->bar('stack')->foobar('overflow'); // need array('hi', 'stack', 'overflow')
// example 3
$c = new Chain();
echo $c->foo('hi')->foobar('overflow'); // prints 'hi-overflow'
// example 4
$c = new Chain();
echo $c->foo('hi')->bar('stack')->foobar('overflow'); // prints 'hi-stack-overflow'
You see, when I want to print the result of chain, I can modify the result in the __toString method, but what if I need an array (example 1, 2)? Is there any way to achieve that without calling some additional "final" method?
Thanks a lot for help and let me know if you need more info.
EDIT: After feedback from #bandi I tried to extend ArrayObject like this.
class Chain extends ArrayObject {
function __call($name, $args) {
$this->append($args[0]);
return $this;
}
function __toString() {
return implode('-', $this->getIterator()->getArrayCopy());
}
}
// returned ref. to object, works fine in loop or accessing offset
$obj = new Chain;
$x = $obj->foo('hi')->bar('stack')->foobar('overflow'); // need array('hi', 'stack', 'overflow')
foreach ($x as $y) {
echo $y, "\n";
}
var_dump($x[0], $x[1], $x[2]);
// returned String
$c = new Chain;
echo $c->foo('hi')->foobar('overflow'); // prints 'hi-overflow'
It does what I wanted, however I don't feel so good about the $this->getIterator()->getArrayCopy() part. Is there some simple way of accessing the array (internally in ["storage":"ArrayObject":private])?
Thanks
Method chaining is using the return value of a function, in this case this is the reference to the object. Predicting the use of a returned value is generally not possible.
You have to tell the called method that you want to do something different. You can use the second argument for this, e.g. you return a different result if the second argument is defined. The other option might be to modify the class so that it behaves like an array except if it is printed.

Categories