How can I check if my object has returned false or not? I have the following class:
class Test {
public function __construct($number) {
if($number != '1') {
return FALSE;
}
}
}
I've tried:
$x = new Test('1');
$x = new Test('2');
But when I var_dump($x), I get the same results. I want to do a:
if(! $x = new Test('1')) {
header("location: xxx...");
}
You cannot return anything from a constructor. If you want the construction of an object to fail, you'll have to throw an Exception.
As deceze said, constructors cannot return a value. You could create a factory method that returns false, like:
class Test
{
public function __construct($number) {
...
}
public function factory($number) {
return ($number != '1') ? false : new self($number);
}
}
$x = Test::factory('1');
if (!$x) {
header('Location: ...');
}
But I would use exceptions instead
class Test
{
public function __construct($number) {
if ($number != '1') {
throw new IllegalArgumentException('Number must be "1"');
}
...
}
}
try {
$x = new Test('1');
} catch (Exception $e) {
header('Location: ...');
}
Related
Say I have to similar function :
public function auth(){
return $someResponse;
}
public function collect(){
return $someOtherResponse
}
Question : When one of the response get passed to another class, is there any way to check which function returned the response ?
In a purely object-oriented way, wanting to attach information to a value is akin to wrapping it into a container possessing context information, such as:
class ValueWithContext {
private $value;
private $context;
public function __construct($value, $context) {
$this->value = $value;
$this->context = $context;
}
public value() {
return $this->value;
}
public context() {
return $this->context;
}
}
You can use it like this:
function auth()
{
return new ValueWithContext($someresponse, "auth");
}
function collect()
{
return new ValueWithContext($someotherrpesonse, "collect");
}
This forces you to be explicit about the context attached to the value, which has the benefit of protecting you from accidental renamings of the functions themselves.
As per my comment, using arrays in the return will give you a viable solution to this.
It will allow a way to see what has been done;
function auth()
{
return (array("auth" => $someresponse));
}
function collect()
{
return (array("collect" => $someotherrpesonse));
}
class myClass
{
function doSomething($type)
{
if (function_exists($type))
{
$result = $type();
if (isset($result['auth']))
{
// Auth Used
$auth_result = $result['auth'];
}
else if (isset($result['collect']))
{
// Collect used
$collect_result = $result['collect'];
}
}
}
}
It can also give you a way to fail by having a return array("fail" => "fail reason")
As comments say also, you can just check based on function name;
class myClass
{
function doSomething($type)
{
switch ($type)
{
case "auth" :
{
$result = auth();
break;
}
case "collect" :
{
$result = collect();
break;
}
default :
{
// Some error occurred?
}
}
}
}
Either way works and is perfectly valid!
Letting the two user defined functions auth() & collect() call a common function which makes a call to debug_backtrace() function should do the trick.
function setBackTrace(){
$backTraceData = debug_backtrace();
$traceObject = array_reduce($backTraceData, function ($str, $val2) {
if (trim($str) === "") {
return $val2['function'];
}
return $str . " -> " . $val2['function'];
});
return $traceObject;
}
function getfunctionDo1(){
return setBackTrace();
}
function getfunctionDo2(){
return setBackTrace();
}
class DoSomething {
static function callfunctionTodo($type){
return (($type === 1) ? getfunctionDo1() : getfunctionDo2());
}
}
echo DoSomething::callfunctionTodo(1);
echo "<br/>";
echo DoSomething::callfunctionTodo(2);
/*Output
setBackTrace -> getfunctionDo1 -> callfunctionTodo
setBackTrace -> getfunctionDo2 -> callfunctionTodo
*/
The above function would output the which function returned the response
Here is my code:
public function call_with_attempts($class_obj, $method_name,array $params = [], $attempts = 5) {
while ($attempts-- > 0) {
try {
if (call_user_func(array($class_obj, $method_name), $params)['result_code'] == '01') {
// log success
return $class_obj->$method_name();
}
throw new Exception("failed");
} catch (Exception $e) {
trigger_error($e->getMessage());
// log the error
}
}
}
I call it like this:
$url = 'www.example.com';
$obj = new Profile($url);
all_with_attempts($obj, 'mymethod');
And here is Profile class:
class profile {
public $url;
public function __construct( $passed_url )
{
$this->url = $passed_url;
}
public function mymethod(){
// do stuff
}
}
Any my code (when I call this function all_with_attempts($obj, 'mymethod');). throws this error:
Missing argument 1 for App\classes\Profile::__construct(), called in {/path}
As you know, this error ^ means Profile class will be create again .. well that's not what I want. I want to use $obj. How can I do that?
I have a system that was designed to do a kind of cascading - get the sequence of methods called upon success of the previous condition.
The example is the below code, which I presume it's not a best practice for doing this, so would be great if I could get some suggestions to refactor this, probably using a design pattern or a different than this system.
<?php
class Model
{
public function isOk()
{
return true;
}
}
class OtherClass
{
public function isOk()
{
return true;
}
}
class AnotherClass
{
public function verifies()
{
return true;
}
}
class Sequence
{
public function fire()
{
$model = new Model();
if($model->isOk()) {
$otherclass = new OtherClass();
if($otherclass->isOk()) {
$anotherclass = new AnotherClass();
if($anotherclass->verifies()) {
echo "We're done with the sequence.";
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
}
$sequence = new Sequence();
echo $sequence->fire();
?>
I would avoid deep nesting of if/else statements to enhance the readability. One way is to use early return:
class Test1
{
public function isOk()
{
echo 'Test1';
return true;
}
}
class Test2
{
public function isOk()
{
echo 'Test2';
return true;
}
}
class Sequence
{
public function fire()
{
$test1 = new Test1();
if (!$test1->isOk()) {
return false;
}
$test2 = new Test2();
if (!$test2->isOk()) {
return false;
}
echo "We're done with the sequence.";
return true;
}
}
If you need it more dynamically you could use call_user_func or call_user_func_array.
class Sequence
{
protected $sequence = array(
array('Test1', 'isOk'),
array('Test2', 'isOk'),
);
public function fire()
{
foreach ($this->sequence as $callback) {
if (!call_user_func(array(new $callback[0], $callback[1]))) {
return false;
}
}
echo "We're done with the sequence.";
return true;
}
}
So I have a class I'm working on to manage PHP sessions, here's the class:
class SessionManagement {
public static function sessionStarted() {
if(session_id() == '') {
return false;
} else {
return true;
}
}
public static function sessionExists($session) {
if(sessionStarted() == false) {
session_start();
}
if(isset($_SESSION[$session])) {
return true;
} else {
return false;
}
}
public static function setSession($session, $value) {
if(sessionStarted() != true) {
session_start();
}
$_SESSION[$session] = $value;
if(sessionExists($session) == false) {
throw new Exception('Unable to Create Session');
}
}
public static function getSession($session) {
if(isset($_SESSION[$session])) {
return $_SESSION[$session];
} else {
throw new Exception('Session Does Not Exist');
}
}
}
Now trying this...
try {
SessionManagement::setSession('Foo', 'Bar');
echo SessionManagement::sessionStarted();
echo SessionManagement::getSession('Foo');
echo SessionManagement::sessionExists('Foo');
} catch(Exception $e) {
echo $e->getMessage();
}
...produces no output...I'm not sure where we're breaking here...any helpful eyes is greatly appreciated...
Unlike other OO languages, like C++, in your class PHP needs to know that the static methods called are from this object. For an instantiated class, that would be through $this, and in your case, static methods, this is done via self:
class SessionManagement {
public static function sessionStarted() {
if(session_id() == '') {
return false;
} else {
return true;
}
}
public static function sessionExists($session) {
if(self::sessionStarted() == false) {
session_start();
}
if(isset($_SESSION[$session])) {
return true;
} else {
return false;
}
}
public static function setSession($session, $value) {
if(self::sessionStarted() != true) {
session_start();
}
$_SESSION[$session] = $value;
if(self::sessionExists($session) == false) {
throw new Exception('Unable to Create Session');
}
}
public static function getSession($session) {
if(isset($_SESSION[$session])) {
return $_SESSION[$session];
} else {
throw new Exception('Session Does Not Exist');
}
}
}
Prepending self:: to all internal calls to the SessionManagement static methods should solve your problem.
Is it possible to create a PHP class that would act like this:
class Foo
{
function __construct($param)
{
if (!is_numeric($param))
{
// stop class
}
}
}
$a = new Foo(2);
$b = new Foo('test');
var_dump($a);
var_dump($b);
which will return
object(Foo)[1]
null
The only way I'm aware of to stop creating of a new object while not immediately terminating the script is to throw an exception:
class Foo {
public function __construct($param) {
if (!is_numeric($param)) {
throw new \InvalidArgumentException('Param is not numeric');
}
...
}
Of course, you'd have to be sure and catch the exception in the calling code and handle the problem appropriately.
Create a static create($param) that returns a new instance or null if $param is invalid. You could also consider using Exceptions.
You could try to throw an exception and catch it from another function in the same scope as the variable declaration:
class Foo
{
function __construct($param)
{
if( !is_numeric($param) )
return true;
else
throw new Exception();
}
}
function createFooObject($v){
try{ $x = new Foo($v); return $x; }
catch(Exception $e){
unset($x);
}
}
$a = createFooObject(2);
$b = createFooObject('test');
var_dump($a);
var_dump($b);
Just return null if the parameter is not numeric:
<?php
class Foo{
public function __construct($param = null){
if( !is_numeric($param) ){
return null;
}
}
}
?>
pretty much as you have it:
<?
public class newClass {
public __CONSTRUCT($param = false){
if(!is_numeric($param)){
return false
}
}
}
$class = new newClass(1);
if($class){
//success / is a number
}else{
// fail, not a number, so remove the instance of the class
unset($class);
}
?>
Setting $param = false inside the arguments for the constructor will tell the script to set it to false if there is no input