Force return statement on caller function - php

I am just curious if it's possible to force parent method to return a value from within method called in that parent method? Let's say I have:
public function myApiEndpoint()
{
// I DO NOT want to to have return statement here
$this->validOrUnprocessable();
// some other code
//return value
return $someValue;
}
public function validOrUnprocessable()
{
if ($condition) {
... here goes the code that forces return statement on myApiEndpoint function without putting the word `return` in front of this call...
}
}
So in other words validOrUnprocessable method, when it needs to do so forces or tricks PHP into thinking that myApiEndpoint returns the value. I do not want to use return statement when validOrUnprocessable is called or any if conditions.
I do know other ways of doing what I want to do but I wanted to know if something like that is possible. I am not interested in any workarounds as I know very well how to implement what I need to achieve in many other ways. I just need to know if this what I described is possible to do exactly how I described it.
I did try to get there with reflections and other scope related things but so far no luck. Any ideas?
Just to add. I am doing this because I want to check how far I can push it. I am building a tool for myself and I want it to be as convenient and easy to use as possible.
If it's not possible I have another idea but that's a bit out of the scope of this post.

You should throw an exception.
public function validOrUnprocessable()
{
if ($condition) {
throw Exception('foo bar');
}
}
The code calling this method should be ready to catch an exception:
public function myApiEndpoint()
{
try {
// I DO NOT want to to have return statement here
$this->validOrUnprocessable();
// some other code
//this code will never be called because of exception thrown in validOrUnprocessable
return value;
} catch (Exception $e) {
//do something else
return -1; //you can return another value as example.
}
return $someValue;
}

Related

Use CodeCeption assertion in conditional (if) statement

I'm totally new with CodeCeption.
I want to do an action/assertion depending on another assertion result, like this:
if ($I->see('message')){
$I->click('button_close');
}
Is something like that possible? I tried, but doesn't work.
Probably the assertion result doesn't apply to IF, but is there any alternative?
Thanks in advance!
IMPORTANT UPDATE:
Finally Codeception now has the function performOn!!
http://codeception.com/docs/modules/WebDriver#performOn
I had this same issue. Although it's not ideal, you can do this:
try {
$I->see('message');
// Continue to do this if it's present
// ...
} catch (Exception $e) {
// Do this if it's not present.
// ...
}
In tests/_support/AcceptanceHelper.php add additional method
function seePageHasElement($element)
{
try {
$this->getModule('WebDriver')->_findElements($element);
} catch (\PHPUnit_Framework_AssertionFailedError $f) {
return false;
}
return true;
}
Then to test in your acceptance test use:
if ($I->seePageHasElement("input[name=address]")) {
$I->fillField("input[name=address]", "IM");
}
You can use a workaround like this or similar combinations:
$tmp = $I->grabTextFrom('SELECTOR');
if ($tmp == 'your text') {
$I->click('button_close');
}
ULTIMATE SOLUTION!
Finally Codeception now has the function performOn, wich does exactly what I asked for!!
[Version 2.2.9]
http://codeception.com/docs/modules/WebDriver#performOn
Answering my example:
$I->performOn('.message', ['click' => '#button_close'], 30);
Waits up to 30 seconds to see the element with class='message', then click the element with id='button_close'.
Codeception now has tryTo..., e.g, tryToSee() trytoClick(), etc., so there's no need for a Try/Catch block. I find it more readable than performOn().
You need to enable it with this in acceptance.suite.yml or codeception.yml:
# enable conditional $I actions like $I->tryToSee()
step_decorators:
- \Codeception\Step\TryTo
- \Codeception\Step\ConditionalAssertion`
You can click on something that may or may not be there with:
$I->tryToClick('#save_button`);
If there's no button, the code goes on with no error message. This could also be used to click on the node to expand a section of a tree before examining it, but only if that section is closed (there should always be a class that's only there when it's closed).
Another way to go is in an if statement. The tryTo... methods all return true on success and false on failure, so you can do this, which some might consider clearer than the above (no error will be thrown):
if ($I->tryToSee('some_locator')) {
$I->click('some_locator');
}
This form is also useful if there is a sequence of actions you want to perform based on a condition, the else is optional.
if ($I->tryToSee('some_locator')) {
$I->fillField('username', 'myname');
$I->fillfield('password', 'mypassword);
$I->click('Submit');
} else {
/* Do something else */
}
Release for my project comes on weeken
/**
* https://stackoverflow.com/questions/26183792/use-codeception-assertion-in-conditional-if-statement
* #param $element
* #return bool
* #throws \Codeception\Exception\ModuleException
*/
public function seePageHasElement($element)
{
$findElement = $this->getModule('WebDriver')->_findElements($element);
return count($findElement) > 0;
}
The reason why the assertion doesn't work with conditional statements is that Codeception first executes the assertion inside the IF brackets, and in case it is not true - it fails the test right away. My way of overcoming this is using the SOFT assertions TryTo which will be ignored by Codeception if fails: https://codeception.com/docs/08-Customization#Step-Decorators
if ($I->tryToSee('message')){
$I->click('button_close');
}```
100% working solution !! Thanx me later ;)
In tests/_support/AcceptanceHelper.php add additional method
public function seePageHasElement($element)
{
try {
$this->getModule('WebDriver')->_findElements($element);
} catch (\PHPUnit_Framework_AssertionFailedError $f) {
return false;
}
return true;
}
Then to test in your acceptance test use:
if ($I->seePageHasElement($element)) {
$I->fillField($element);
}
The 'seeElement' function of WebDriver doesnot work on this case so needs little modified function as i have used one '_findElements' .Please donot forget to build your actors after any changes done.

Build a UnitTest with multiple options on the same mocked-method

I have a problem to test a Method like that
public function index(){
if($this->request->is('get')){
if($this->Session->check('saveConflict')){
$this->set('conflict',true);
}else{
$this->set('data','test');
}
if($this->Session->check('full')){
$this->set('data',$this->Model->find('all'));
}else{
$this->set('data','test');
}
}else{
throw new BadRequestException;
}
}
unless that method maybe doesn't make sense, here is my problem. I have to call the method "check" on the Session-Component twice. But I want that for example the first methode mock-call retruns a "false" and the second a "true".
Here's what I have
$this->Editors->Session
->expects($this->once())
->method('check')
->will($this->returnValue(true));
I've tried it with the expectation "$this->at(1)" the call via order-index. But i think that isnt pretty clever because if I add a Session->check anywhere in the interpreted way though my base-method for example i have to change all those test-lines to make it work properly again.
I use CakePHP 2.4.6 and php-unit 4.1.3.
Is there any other why to do what I want to do?
Use the
->will($this->onConsecutiveCalls(array('return_value1',
'retur_value2',
...)));
Give the sequence of the return value in the order you want, the mocked method will return it in order.Or you can try the $this->returnCallback to do some sophisticated customize.You can find the example here How can I get PHPUnit MockObjects to return differernt values based on a parameter?.
Example
If you just want to do the unit test and cover all the path,I'll do like this:
public function testIndex()
{
....
$this->Editors->Session
->expects($this->any())
->method('check')
->will($this->returnCallback(array($this,'sessionCallback')));
$this->object->index();
$this->object->index();
.....
}
private $sessionFlag;
public function sessionCallback($value)
{
$rtnValue = $this->sessionFlag[$value];
$this->sessionFlag[$value] = (!$rtnValue);
return $rtnValue;
}

use goto inside function php

Is there a way to define global label (something like variables) for PHP goto, in order to use it inside function declaration. I want to do the following:
function myFunction() {
if (condition) {
goto someLine;
}
}
someLine:
// ....
myFunction();
when I use this code it says
PHP Fatal error: 'goto' to undefined label "someLine"
I know that it is not recommended to use goto statement. But I need it in my case. I know that perhaps always there are alternatives of goto, just in my case it would make the code a little easier and understandable
You cannot goto outside of a function I believe: http://php.net/manual/en/control-structures.goto.php
Direct Quote:
This is not a full unrestricted goto. The target label must be within the same file and context, meaning that you cannot jump out of a function or method, nor can you jump into one.
This might have to do with the fact that php is parsed and jumping out of a function will cause a memory leak or something because it was never properly closed.
Also as everyone else said above, really you don't need a goto. You can just return different values from the function and have a condition for each. Goto is just super bad practice for modern coding (acceptable if you are using basic).
Example:
function foo(a) {
if (a==1) {
return 1;
} elseif (a==3) {
return 2;
} else {
return 3;
}
}
switch (foo(4)) { //easily replaceable with elseif chain
case 1: echo 'Foo was 1'; break; //These can be functions to other parts of the code
case 2: echo 'Foo was 3'; break;
case 3: echo 'Foo was not 1 or 3';
}
There's no way to jump in or out of a function. But since you state that you need it, here's an alternative route.
function myFunction() {
if (condition) {
return true;
}
return false;
}
someLine:
// ....
$func = myFunction();
if($func == true) goto someLine;
As previously stated you can't. As for "I need it", I highly doubt this. Whatever code you have at someLine: can easily be made into a function that you can call from the other if needed.
yeah there's a way as long as that function is declared on the same php file or is included if its on another script,
the best way to jump on to someline is to return that goto code of yours dude so that if function is called a return value is received.. hope this helps
function foo($b="30")
{
$a=30;
if($a==intval($b))
return "someline:goto
someline";
}
try{
eval(foo());
}
catch(IOException $err)
{
exit($err);
}
/*someline is somewhere here
for example */

Start function over, depending on results of IF statement

If I have a function that is inside of a Class, and I am returned with "invalid" how can I start back up at the top function?
function test(){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
continue ;
}
}
but I get the following error
Fatal error: Cannot break/continue 1 level in
If I am hit with "invalid" I would like to start test() back over..
You probably want to use a recursive function here:
function test(){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
return test() ; // restart process
}
}
Alternatively, this may be a (very rare) good use of the goto operator:
function test(){
start:
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
goto start;
}
}
Note that this will only work in PHP >=5.3.
I'd make use of exceptions, and let the calling scope control repeat invocations of test(). test() performs one job; it shouldn't control when it's asked to perform that job.
(Recursive approaches given in other examples don't really fit the use case [and make me nervous, thanks to languages where recursing too many times makes you run out of stack space eventually; certainly you're filling up your stack for no reason], and though goto will work fine it still gives the function itself too much power.)
function test()
{
//curl here
//other stuff here
if (strpos($data, 'invalid'))
throw new Exception("Data is invalid");
}
function callingFunction()
{
while (true) {
try {
test();
break; // only reached if test() didn't throw
}
catch(Exception $e) {} // if we fall into this, the loop repeats
}
}
You could still apply goto quite cleanly with this approach:
function test()
{
//curl here
//other stuff here
if (strpos($data, 'invalid'))
throw new Exception("Data is invalid");
}
function callingFunction()
{
startTest:
try {
test();
}
catch(Exception $e) {
goto startTest;
}
}
Remove continue; and instead add test();. It's called recursive functions (calling itself).
There are a few ways you can do it, the way my teacher normally suggests is to actually call the function again.
function test(){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove continue ;
test();
return;
}
}
My answer might not be the best, hope this helps.
Assuming you change the parameters beforehand, you can recursively call the function again with new parameters. Just make sure there will be an edge case where the function will stop recursing. As for that, I'd need to see the real code to tell you.
function test($data){
//curl here
//other stuff here
if(strpos($data, 'invalid')){
print "invalid";
//discard and remove
test($NEW_DATA);
}
}
If you want to break out of the function you're currently in, you should use 'return' instead of 'continue'.
Or if you would like to start the processing over, you should put your logic into a loop.

Is it possible to make an object return false by default?

I tried to ask this before, and messed up the question, so I'll try again. Is it possible to make an object return false by default when put in an if statement? What I want:
$dog = new DogObject();
if($dog)
{
return "This is bad;"
}
else
{
return "Excellent! $dog was false!"
}
Is there a way this is possible? It's not completely necessary, but would save me some lines of code. thanks!
No, PHP has no support for operator overloading. Maybe they'll add it in a future version.
Use the instanceof keyword.
For example
$result = Users->insertNewUser();
if($result instanceof MyErrorClass){
(CHECK WHAT WENT WRONG AND SAY WHY)
} else {
//Go on about our business because everything worked.
}
Info is here.
Use this? Not a real neat solution, but does what you want:
<?php
class Foo
{
private $valid = false;
public function Bar ( )
{
// Do stuff
}
public function __toString ( )
{
return ( $this -> valid ) ? '1' : '0';
}
}
?>
Zero is considered false, one is considered true by PHP
I was attempting to do this myself and found a solution that appears to work.
In response to the others who were trying to answer the question by telling the asker to use a different solution, I will also try to explain the reason for the question. Neither the original poster or I want to use an exception, because the point is not to use exception handling features and put that burden on any code we use this class in. The point, at least for me, was to be able to use this class seamlessly in other PHP code that may be written in a non-object-oriented or non-exception-based style. Many built-in PHP functions are written in such a way that a result of false for unsuccessful processes is desirable. At the same time, we might want to be able to handle this object in a special way in our own code.
For example, we might want to do something like:
if ( !($goodObject = ObjectFactory::getObject($objectType)) ) {
// if $objectType was not something ObjectFactory could handle, it
// might return a Special Case object such as FalseObject below
// (see Patterns of Enterprise Application Architecture)
// in order to indicate something went wrong.
// (Because it is easy to do it this way.)
//
// FalseObject could have methods for displaying error information.
}
Here's a very simple implementation.
class FalseObject {
public function __toString() {
// return an empty string that in PHP evaluates to false
return '';
}
}
$false = new FalseObject();
if ( $false ) {
print $false . ' is false.';
} else {
print $false . ' is true.';
}
print '<br />';
if ( !$false ) {
print $false . ' is really true.';
} else {
print $false . ' is really false.';
}
// I am printing $false just to make sure nothing unexpected is happening.
The output is:
is false.
is really false.
I've tested this and it works even if you have some declared variables inside the class, such as:
class FalseObject {
const flag = true;
public $message = 'a message';
public function __toString() {
return '';
}
}
A slightly more interesting implementation might be:
class FalseException extends Exception {
final public function __toString() {
return '';
}
}
class CustomException extends FalseException { }
$false = new CustomException('Something went wrong.');
Using the same test code as before, $false evaluates to false.
I recently had to do something similar, using the null object pattern. Unfortunately, the null object was returning true and the variable in question was sometimes an actual null value (from the function's default parameter). The best way I came up with was if((string)$var) { although this wouldn't work for empty arrays.
Putting something in "an if statement" is simply evaluating the variable there as a boolean.
In your example, $dog would need to be always false for that to work. There is no way to tell when your variable is about to be evaluated in a boolean expression.
What is your ultimate purpose here? What lines of code are you trying to save?
I'm not sure about the object itself. Possible. You could try something like, add a public property to the DogObject class and then have that set by default to false. Such as.
class DogObject
{
var $isValid = false;
public function IsValid()
{
return $isValid;
}
}
And then when you would instantiate it, it would be false by default.
$dog = new DogObject();
if($dog->IsValid())
{
return "This is bad;"
}
else
{
return "Excellent! $dog was false!"
}
Just a thought.
If I understand what your asking, I think you want to do this:
if (!$dog){
return "$dog was false";
}
The ! means not. SO you could read that, "If not dog, or if dog is NOT true"
Under what conditions do you want if($dog) to evaluate to false? You can't do what you've literally asked for, but perhaps the conditioned could be replaced by something that does what you want.
class UserController
{
public function newuserAction()
{
$userModel = new UserModel();
if ($userModel->insertUser()) {
// Success!
} else {
die($userModel->getError());
}
}
}
Or
class UserController
{
public function newuserAction()
{
$userModel = new UserModel();
try {
$userModel->insertUser()
}
catch (Exception $e) {
die($e);
}
}
}
There are a million ways to handle errors. It all depends on the complexity of the error and the amount of recovery options.
How about using an Implicit Cast Operator like the following C# ?
like so:
class DogObject
{
public static implicit operator bool(DogObject a)
{
return false;
}
}
Then you can go...
var dog = new DogObject();
if(!dog)
{
Console.WriteLine("dog was false");
}

Categories