Is this always safe or could it cause errors in some cases?
if(isset($myVar) && $myVar->myProp !== 'error') {
...
This seems to be a case of defining properties on the fly. While it's possible (and valid) to use property_exists(), it would be much better to actually enforce the existance of the property in the class definition:
Class someExample {
public $myProp = false; // now it will ALWAYS exist for any instance of someExample
}
Yes, it will cause an error if the property doesn't exist. Check it exists with property_exists
$myVar = new myVar();
if( (isset($myVar) && property_exists('myVar', 'myProp'))
&& $myVar->myProp !== 'error' ) {
}
Related
I need to know if there is a better way to avoid Call to a member function xxxx() on null
currently I'm coding as follows but it is cumbersome.
if($event->getForm()
&& $event->getForm()->getParent()
&& $event->getForm()->getParent()->getParent()
&& $event->getForm()->getParent()->getParent()->getData()
&& $event->getForm()->getParent()->getParent()->getData()->getComponente()
){
$componente = $event->getForm()->getParent()->getParent()->getData()->getComponente();
$formModifier($event->getForm(), $componente, $defaultComponente);
}
In PHP 7 this is actually a catchable Error (if you're using hhvm it's a regular Exception):
try {
$componente = $event->getForm()->getParent()->getParent()->getData()->getComponente();
} catch (\Error $e) {
$componente = null;
}
if ($componente !== null) {
$formModifier($event->getForm(), $componente, $defaultComponente);
}
In PHP 5 there is a workaround using intermediate variables and the and keyword instead of &&:
if (
$f = $event->getForm() and
$p = $f->getParent() and
$p2 = $p->getParent() and
$d = $p2->getData() and
$componente = $d->getComponente()
) {
$formModifier($f, $componente, $defaultComponente);
}
If you use && instead of and you'll get "undefined variable" notices and this workaround won't work.
Working examples: https://3v4l.org/0S6ps
no there is no way, but at least you can do some performance improvement
$form = $event->getForm();
if(!$form){
//do error handling
return;
}
$parent = $form->getParent();
if(!$parent){
//do error handling
return;
}
$p_parent = $parent->getParent();
if(!$p_parent){
//do error handling
return;
}
$data = $p_parent->getData();
if(!$data){
//do error handling
return;
}
$component = $data->getComponente();
...
this way you call each function only once and you can do better error handling
I think this is a great example of a bad code. By having a code like this you're breaking several rules and making your life much harder than it should be.
Your code is rigid, fragile, hard to understand and maintain etc.
Simpler is ALWAYS better.
If you can't make your $xx->getComponent() a proper object easily accessible without such ugly nested relationship, you should at least encapsulate the method into something appropriate and use that instead, so if anything changes, you don't have to go full mental and change it all over the place.
This class seems strange in it's creation, but if you are not extracting these methods dynamically using __call(), you can use method_exists() in a loop inside a function, something similar to:
function getMethodChain($class,$arr = ['getForm','getParent','getParent','getData','getComponente'])
{
# First check the object is set
if(!is_object($class))
return false;
# Loop intended method chain
foreach($arr as $method) {
# Check if the method exists in the current class or passed already
$useClass = (!isset($classPass))? $class : $classPass;
# Check if the method exists in the current class
if(is_object($useClass) && method_exists($useClass,$method)) {
# Assign this class/method to use next in the loop
$classPass = $useClass->{$method}();
}
else
return false;
}
# Just send back
return (isset($classPass))? $classPass : false;
}
The use would be something like:
# This will either be the data you expect or false
$componente = getMethodChain($event);
I am trying to design a Database($db) Mock with Atoum that would return different values depending on previous method calls (and arguments).
I'm using PHP 5.6 and Atoum 3.2
Here is what I tried:
$this->calling($db)->select = function($table, array $bind, $boolOperator = "AND") use ($permissionClientMapper, $db, $permissionsClientRaw){
if($table === $permissionClientMapper->getTableName()){
$this->calling($db)->fetchAll = function() use ($bind, $permissionsClientRaw){
if(array_key_exists('type_service', $bind) && array_key_exists('id_service', $bind) && $bind['type_service'] === 'mutu' && $bind['id_service'] === 4012){
return EXPECTED_RETURN_VALUE;
}
return null;
};
}
};
I would except the code to return the EXECTED_RETURN_VALUE when I call (with arguments):
1/ $db->select() -> This method is called as expected
2/ $db->fetchAll() -> This one is never called
I didn't find any example of this in the Atoum documentation.
Can someone confirm this is the correct way to mock successive method calls ?
I also tried to use a reference to the database in the closure
$this->calling($db)->select = function($table, array $bind, $boolOperator = "AND") use ($permissionClientMapper, &$db, $permissionsClientRaw){
if($table === $permissionClientMapper->getTableName()){
$this->calling($db)->fetchAll = function() use ($bind, $permissionsClientRaw){
if(array_key_exists('type_service', $bind) && array_key_exists('id_service', $bind) && $bind['type_service'] === 'mutu' && $bind['id_service'] === 4012){
return EXPECTED_RETURN_VALUE;
}
return null;
};
}
};
But this doesn't work either.
Edit: One workaround would probably be to use the atoum call order to return different values for each call, and then to test the mock to check it was called with the correct arguments.
I will give you some insight about your questions and hope give you some clue to find a way to solve it.
So to validate that a mock method is not called, you can use 'call' with 'never'
$this->mock($mock)->call('fetchAll')->never();
And to be called :
$this->mock($mock)->call('select')->once();
To deal with you mock answer, you can use several things, like this
$this->calling($db)->fetchAll[0] = null; // default answer
$this->calling($db)->fetchAll[1] = function () {....} // first call to method
If you want something like a chain : when use the mocked method select, and inside it we call fetchAll method then the answer is ... atoum doesn't offer yet this behavior. The best is to create an issue exposing your case.
When you use 'calling' you define the behavior of the mock. It's only when the method is called, that atoum will grab everything and resolve it.
So for me, if I understand correctly your question, I will write it like that :
$this->calling($db)->fetchAll = function() use ($bind){
if(array_key_exists('type_service', $bind) && array_key_exists('id_service', $bind) && $bind['type_service'] === 'mutu' && $bind['id_service'] === 4012){
return EXPECTED_RETURN_VALUE;
}
return null;
};
$this->calling($db)->select = function($table, array $bind, $boolOperator = "AND") use ($permissionClientMapper, $db){
if($table === $permissionClientMapper->getTableName()){
return $db->fetchAll();
}
};
// this is the same as your code. But It a bit more readable
$this->newTestedInstance;
$this->testedInstance->setDb($db);
$this->variable($this->testedInstance->doTheCallThatReturnNull())
->isEqualTo(null);
// do some change in the vars to be in the value
$this->variable($this->testedInstance->doTheCallThatReturnValue())
->isEqualTo(EXPECTED_RETURN_VALUE);
ps : to help you going further you can read http://docs.atoum.org/en/latest/asserters.html#mock and http://docs.atoum.org/en/latest/mocking_systems.html
and you can also tag the question with 'atoum'.
I have method in class:
class SomeClass{
public function someMethod($status){
echo $status;
}
}
I know what $status can be 1 or 0.
Is it possible to force method work only with that values? So for code:
$class = new SomeClass();
$class->someMethod(2);
get some error (fatal, warning, notice).
P.S. if($status != 1 && $status != 2) is not good solution for me.
U can use assert function, but if statement is better
Any idea if PHP's memcached module supports some kind of isset() method?
Following case:
Memcached::set('foo', false);
if(Memcached::get('foo') === false) {
// Set or not set?
}
according to the documentation
if($memcached->get('var') === false && $memcached->getResultCode() == Memcached::RES_NOTFOUND){
//not set
}
You can of course extend the Memcached object to include it, however, you can't ask if it's set without getting it (some overhead on larger values):
class YourMemcached extends Memcached {
function var_isset($var){
return $this->get($var)!==false || $this->getResultCode() != Memcached::RES_NOTFOUND;
}
}
(you can't use isset as a method name as it's a language construct apparently).
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");
}