How to implement variable with value operator statement in IF statement ?
if ($dcustomer['mix_max']=='MIN') {
$operator=">=";
} elseif ($dcustomer['mix_max']=='MAX') {
$operator="<=";
}
if ($djml['Tamount'] ."$operator". $dcustomer['limit_maksimal']){
}
<?php
$dcustomer = array("mix_max"=>"MIN","limit_maksimal"=>2);
$djml = array("Tamount"=>"");
if ($dcustomer['mix_max']=='MIN') {
$operator=">=";
} elseif ($dcustomer['mix_max']=='MAX') {
$operator="<=";
}
echo $djml['Tamount'] .$operator. $dcustomer['limit_maksimal'];
You cannot (well, you could if you used eval(), which should be avoided for obvious reasons).
But the same effect can be achieved with a multiplier:
switch ($dcustomer['mix_max']) {
case 'MIN':
$multiplier = 1;
break;
case 'MAX':
$multiplier = -1;
break;
default:
// Always prepare for the unknown :-)
throw new \Exception("Unknown operator");
}
if ($djml['Tamount']*$multiplier >= $dcustomer['limit_maksimal']*$multiplier) {
...
}
But I think it would be clearer and more flexible:
$condition = null;
switch ($dcustomer['mix_max']) {
case 'MIN':
$condition = ($djml['Tamount'] >= $dcustomer['limit_maksimal']);
break;
case 'MAX':
$condition = ($djml['Tamount'] <= $dcustomer['limit_maksimal']);
break;
default:
// Always prepare for the unknown :-)
throw new \Exception("Unknown operator");
}
if ($condition) {
...
}
Related
Hy,
I got switch case inside function when but when i call it, i got error Undefined Variable and i don't know why (i use PHP 8)
private function getIDFromBrand() {
switch ($this->brand) {
case "Niky":
$id = 1;
break;
case "Pumo":
$id = 4;
break;
case "Coke":
if ($this->typecoke== 0) {
$id = 2;
} else {
if ($this->typecoke== 1) {
$id = 3;
}
}
break;
case "Tomato":
$id = 5;
break;
case "Riles":
$id = 6;
break;
case "TEST":
$id = 7;
break;
}
return $id; // Error Undefined variable $id
}
When i declare $id at the top of my function, like
$id = null
or
$id = 0
The switch doesn't update it, so it will return null or 0, it will return the declared value.
Your switch statement has no default branch, so if $this->brand is, say, "Stack Overflow", it will not run any of the statements, and $id will never be set.
See the PHP manual for the switch statement:
A special case is the default case. This case matches anything that wasn't matched by the other cases.
Similarly, if $this->brand is "Coke", but $this->typecoke is, say, 42, it will not match either of the conditions in that branch.
switch ($this->brand) {
case "Niky":
$id = 1;
break;
case "Pumo":
$id = 4;
break;
case "Coke":
if ($this->typecoke== 0) {
$id = 2;
} elseif ($this->typecoke== 1) {
$id = 3;
} else {
$id = -1; // WAS PREVIOUSLY NOT SET
}
break;
case "Tomato":
$id = 5;
break;
case "Riles":
$id = 6;
break;
case "TEST":
$id = 7;
break;
default:
$id = -1; // WAS PREVIOUSLY NOT SET
break;
}
It is possible to go to default case from within some other case like this?
$a = 0;
$b = 4;
switch ($a) {
case 0:
if ($b == 5) {
echo "case 0";
break;
}
else
//go to default
case 1:
echo "case 1";
break;
default:
echo "default";
}
I tried to remove the else and was expecting that it would continue evaluating all following cases until default but it gets into case 1 then. Why is it so and how can I get to the default one?
Yes you can if you reorder the case statements:
switch ($a) {
case 1:
echo "case 1";
break;
case 0:
if ($b == 5) {
echo "case 0";
break;
}
default:
echo "default";
}
Why is it so:
it is defined, if you de not have a break statement the next case will be executed. If there is no more case, the default will be executed if one is defined
You could re-order the case statements to allow a fall through to the next option, but if there are several times you wish to do this it can become impossible or just very fragile. The alternative is to just more the common code into a function...
function defaultCase() {
echo "default";
}
switch ($a) {
case 0:
if ($b == 5) {
echo "case 0";
}
else {
defaultCase();
}
break;
case 1:
echo "case 1";
break;
default:
defaultCase();
}
I would suggest using a simple if / else as I mentioned in the comments.
However, here's another way you could do it using a switch statement, if that helps:
switch ([$a, $b]) {
case [0, 5]:
echo 'case 0';
break;
case [1, $b]:
echo 'case 1';
break;
default:
echo 'default';
}
I have this method:
private function convertStatusStringToIntZeroOrOne(string $status)
{
$status = strtolower($status);
switch ($status) {
case "off":
case "0":
case 0:
$int_status = 0;
break;
case "on":
case "1":
case 1:
$int_status = 1;
break;
default:
$int_status = 1;
break;
}
return $int_status;
}
The $status parameter, when is the string "On" (with O letter capitalize), return 0 (zero).
Of course, I need return as 1.
Thank you
As you had numeric 0 and 1 in the options of the switch it was using a numeric comparison - "on" to a number is 0 and so it matched against 0.
As you have the parameter as type string a number would be converted to a string, so remove the numeric comparisons...
function convertStatusStringToIntZeroOrOne(string $status)
{
$status = strtolower($status);
switch ($status) {
case "off":
case "0":
$int_status = 0;
break;
case "on":
case "1":
$int_status = 1;
break;
default:
$int_status = 1;
break;
}
return $int_status;
}
echo convertStatusStringToIntZeroOrOne("On");
Although you could reduce the function to...
function convertStatusStringToIntZeroOrOne(string $status)
{
$status = strtolower($status);
return ($status == "off" || $status == 0)?0:1;
}
I don't quite understands this.. Take a look at the following:
$value = 0;
if($value >= 90) {
// this does not return true
}
switch($value) {
case $value >= 90:
// this however does
break;
}
Am i missing something very obvious ?
$value >= 90 evaluates to false
As $value is 0, it is considered false. That's why your case works.
In a simple way it can be rewritten as:
switch($value) {
case false:
// this works
break;
}
I wrote a class for badge activation and it should be refactored now.
Are there any good advices, how should I refactor it's trigger() method?
The source of the class is in github:
https://github.com/heal25/ced/blob/master/models/BadgeActivator.php
The problematic method:
public function trigger($id, $data = []) {
if (!$this->_uid) $this->setUid(Yii::app()->player->model->uid); //set default uid
$activate = false;
switch ($id) {
//case 'login_1': $activate = true; break;
case 'max_nrg_35': if ($data['energy_max'] >= 35) $activate = true; break;
case 'max_nrg_100': if ($data['energy_max'] >= 100) $activate = true; break;
case 'skill_35': if ($data['skill'] >= 35) $activate = true; break;
case 'skill_100': if ($data['skill'] >= 100) $activate = true; break;
case 'strength_35': if ($data['strength'] >= 35) $activate = true; break;
case 'strength_100': if ($data['strength'] >= 100) $activate = true; break;
case 'energy_drink': $activate = true; break;
case 'level_10': if ($data['level'] >= 10) $activate = true; break;
case 'level_100': if ($data['level'] >= 100) $activate = true; break;
case 'dollar_50': if ($data['dollar'] >= 50) $activate = true; break;
case 'dollar_5000': if ($data['dollar'] >= 5000) $activate = true; break;
case 'travel_loc3': if ($data['water_id'] == 3) $activate = true; break;
case 'travel_county2': if ($data['county_id'] == 2) $activate = true; break;
case 'travel_county9': if ($data['county_id'] == 9) $activate = true; break;
case 'routine_100': if ($data['routine'] >= 100) $activate = true; break;
case 'loc_routine_4b': if ($data['water_id']==4 and $data['routine'] > 0) $activate = true; break;
case 'loc_routine_13s': if ($data['water_id']==13 and $data['routine'] >= 3) $activate = true; break;
case 'loc_routine_28s': if ($data['water_id']==28 and $data['routine'] >= 3) $activate = true; break;
case 'loc_routine_37g': if ($data['water_id']==37 and $data['routine'] >= 9) $activate = true; break;
case 'loc_routine_52b': if ($data['water_id']==52 and $data['routine'] > 0) $activate = true; break;
case 'loc_routine_61s': if ($data['water_id']==61 and $data['routine'] >= 3) $activate = true; break;
case 'loc_routine_71g': if ($data['water_id']==71 and $data['routine'] >= 9) $activate = true; break;
case 'loc_routine_72e': if ($data['water_id']==72 and $data['routine'] >= 27) $activate = true; break;
case 'loc_routine_46d': if ($data['water_id']==46 and $data['routine'] >= 81) $activate = true; break;
case 'setpart_3': if ($data['cnt'] >= 3) $activate = true; break;
case 'setpart_10': if ($data['cnt'] >= 10) $activate = true; break;
case 'setpart_30': if ($data['cnt'] >= 30) $activate = true; break;
case 'first_duel_win': if ($data['role'] == 'caller' and $data['winner'] == 'caller') $activate = true; break;
case 'duel_success_100': if ($data['cnt'] >= 100) $activate = true; break;
case 'duel_fail_100': if ($data['cnt'] >= 100) $activate = true; break;
case 'duel_rate_40': if ($this->getSuccessRate(100, $data) <= 40) $activate = true; break;
case 'duel_rate_25': if ($this->getSuccessRate(300, $data) <= 25) $activate = true; break;
case 'duel_rate_10': if ($this->getSuccessRate(600, $data) <= 10) $activate = true; break;
case 'duel_rate_60': if ($this->getSuccessRate(100, $data) >= 60) $activate = true; break;
case 'duel_rate_75': if ($this->getSuccessRate(300, $data) >= 75) $activate = true; break;
case 'duel_rate_90': if ($this->getSuccessRate(900, $data) >= 90) $activate = true; break;
case 'duel_money_100': if ($data['dollar'] >= 100) $activate = true; break;
case 'duel_money_1000': if ($data['dollar'] >= 1000) $activate = true; break;
case 'duel_win_chance35': if ($data['winner'] and $data['chance'] <= 35) $activate = true; break;
case 'duel_win_chance20': if ($data['winner'] and $data['chance'] <= 20) $activate = true; break;
case 'duel_win_chance5': if ($data['winner'] and $data['chance'] <= 5) $activate = true; break;
case 'duel_lose_chance65': if (!$data['winner'] and $data['chance'] >= 65) $activate = true; break;
case 'duel_lose_chance80': if (!$data['winner'] and $data['chance'] >= 80) $activate = true; break;
case 'duel_lose_chance95': if (!$data['winner'] and $data['chance'] >= 95) $activate = true; break;
case 'duel_2h': if ($data['role'] == 'caller' and date('G')==2) $activate = true; break;
case 'shop_item10': if (Yii::app()->player->model->owned_items >= 10) $activate = true; break;
case 'shop_bait20': if (Yii::app()->player->model->owned_baits >= 20) $activate = true; break;
case 'set_b': if ($data['id']==1) $activate = true; break;
case 'set_s': if ($data['id']==2) $activate = true; break;
case 'set_g': if ($data['id']==3) $activate = true; break;
case 'set_sell_b': if ($data['id']==1) $activate = true; break;
case 'set_sell_s': if ($data['id']==2) $activate = true; break;
case 'set_sell_g': if ($data['id']==3) $activate = true; break;
case 'club_join': $activate = true; break;
case 'club_create': $activate = true; break;
case 'club_members_8': if ($data['cnt'] >= 8) $activate = true; break;
case 'login_days_7': if ($this->getLoginDays() >= 7) $activate = true; break;
case 'login_days_30': if ($this->getLoginDays() >= 30) $activate = true; break;
case 'login_days_60': if ($this->getLoginDays() >= 60) $activate = true; break;
case 'win_contest': $activate = true; break;
}
if ($activate) {
return $this->activate($id);
}
return false;
}
I can extract the activations for 'loc_routine_*' cases, but it isn't much.
I'm not familiar with Yii, but from glancing over their docs, you could probably refactor the trigger method to make use of Yii Validators and the DI container. Something along these lines:
class BadgeActivator
…
public function trigger($id, array $data)
{
$badgeValidator = $this->badgeValidators->findById($id);
if ($badgeValidator->validate($data)) {
$this->activate($id);
}
}
}
The BadgeValidators object is a simple collection of objects implementing the BadgeValidator interface. You need to inject this to your BadgeActivator.
class BadgeValidators
{
private $validators = [];
public function __construct(array $badgeValidators)
{
foreach ($badgeValidators as $badgeValidator) {
$this->addBadgeValidator($badgeValidator);
}
}
public function addBadgeValidator(BadgeValidator $badgeValidator)
{
$this->validators[$badgeValidator->getId()] = $badgeValidator;
}
public function findById($badgeId)
{
if (isset($this->validators[$badgeId])) {
return $this->validators[$badgeId];
}
throw new BadgeValidatorNotFoundException(
"No BadgeValidator found for badge id [$badgeId]"
);
}
}
The BadgeValidator interface is the contract all concrete validators need to obey. Their purpose is to map from $data to Yii's build in validators or to encapsulate additional/unique validation logic.:
interface BadgeValidator
{
public function getId();
public function validate($value = null);
}
A concrete Validator would then look like this:
class MaxEnergy35 implements BadgeValidator
{
public function getId()
{
return 'max_nrg_35';
}
public function validate($value = null)
{
$validator = new yii\validators\IntegerValidator();
$validator->min = 35;
return $validator->validate($value['max_energy']);
}
}
You could move the configuration for this class to the DI config as well, e.g. you could inject maxEnergy, validatorId and the Yii Validator. If you do that, you'll only have one class MaxEnergy instead of MaxEnergy35 and MaxEnergy100. For sake of simplicity, I'll keep it this way now.
Here is one with custom logic:
class DuelRate40 implements BadgeValidator
{
public function getId()
{
return 'duel_rate_40';
}
public function validate()
{
return $this->getSuccessRate(100, $data) <= 40;
}
private function getSuccessRate($limit, array $data)
{
// moved from BadgeActivator
}
}
As you can see, it's trivial to make your BadgeValidators with custom logic and without using the Yii validators. In this particular case, I just moved the getSuccessRate rate method to the validator. You could easily see that it's misplaced on the BadgeActivator because it didn't have any cohesion to any class properties. Obviously, if you need this code in multiple validations, you could make it configurable again, so you have only one validator of that kind, instead of duplicating that method in each concrete one.
Now, for each case in your switch/case, simply add another concrete BadgeValidator and inject it to the BadgeValidators in the DIConfig.
In your ced/config/main.php:
// more config …
components => [
'badgeValidator' => [
'class'=> 'application.components.BadgeValidator',
'badgeValidators' => [
['class'=>'MaxEnergy35'],
['class'=>'MaxEnergy100'],
['class'=>'DuelRate40'],
// more validators …
]
],
// other components …
]
Note: I have no clue if this is the correct way to use Yii's DI config. I am just assuming from your file on GitHub. But I guess, you'll know how to change it if necessary.
And whenever you need to add a new Badge, you simply write the Validator and wire it up in the config. You will never need to touch the BadgeActivator again. This will also significantly lower the Cyclomatic Complexity of the BadgeActivator. And it's trivial to add Unit Tests for each of the components above.