-1

I have to transfer a lot of old procedural code to OOP in Laravel.

In this code there are hundreds of dynamically-generated arrays, which come form many nested ifs, foreachs etc.

Vanilla PHP doesn’t complain and gives only a notice, but Laravel throws an error for this:

$arr[$month][$year][$bla][$blablbalba] += $v;

The problem is in +=.

Of course I can easily solve this problem with:

if (! isset($blabla)) {
   // set it
}

The problem is that there are more than 250 arrays generated, and I don’t want to write 250 ifs.

I tried to use the magic methods __get() and __set(), but there is an issue with the __set() method when you try something as:

$this->someProperty['key1']['key2'] 

Getting “Indirect modification of overloaded property” message.

This is more PHP-specific problem, it’s not much Laravel-related, but Laravel in my case is the barrier that shows this bad practice in the old code and throws and error.

How can I solve this problem, without writing ifs like crazy? Just want to mention one more time that the arrays are dynamically-generated and differently nested, depending on conditional logic. I can’t define all of them in the beginning of the methods of the class.

Is there a clever way to do it, or the business logic of the code has to be completely changed (very bad scenario)? Thank you in advance. I appreciate the time devoted.

Here is one of the many foreach loops where these arrays are generated:

$heating_appliances = $haClass->calculateHA($scenario, $house_type, $year, $hd, $has, $ha_rp, $ha_dhp, $ha_chp, 'total_month', $extra_devices, $options);
foreach($heating_appliances[$year[0]] as $month => $classes) {
    foreach($classes as $class => $energy) {
        if(count(array_intersect($extra_devices, $groupsData[$class]['devices']))) {
            if($group_type == 'total_co2') {
                $profiles[$month][$class] += round((($energy * $co2[$class]) / 1000) * $energy_factor[$class], 3);
            } else {

                $profiles[$month][$class] += round($energy * $energy_factor[$class], 3);
            }
        }
    }
} 
  • You have not really given us much real info to go on here. But one thing that occurs to me is that maybe you are not passing this data correctly to the new OOP code you have written i.e. ___Is it a scope issue___ – RiggsFolly Jul 17 '17 at 13:13
  • I myself am not fluent in the language of *blah*. – Funk Forty Niner Jul 17 '17 at 13:14
  • How do you work with `__get()` and `__set()` on arrays, to start with? Are they arrays or objects? – M. Eriksson Jul 17 '17 at 13:15
  • `+= $v;` if you're not trying to do math here but rather to concatenate, you need to use `.= $v;` question's unclear in that respect. Too many *blah's* for my taste and what those *blah values* really are. – Funk Forty Niner Jul 17 '17 at 13:17
  • you've been asked a few questions and just like yours, expect to get some answers. I've yet to see anyone pinged back for them yet, unless you left the question. voting to close – Funk Forty Niner Jul 17 '17 at 13:21
  • @MagnusEriksson, properties in objects can be arrays, right? My idea was to get and set these properties(which are arrays) trough __get and __set to avoid all those ifs. – Miro Xristov Jul 17 '17 at 13:26
  • Maybe can use a combination of laravel helpers - specifically array_set and array_get. [Helpers](https://laravel.com/docs/5.0/helpers). Let me know if that will help I will formulate it as an answer then. – Artur K. Jul 17 '17 at 13:28
  • Yes, but like the previous comments already mentioned, you need to give us all the info about the code you're having issues with. There's not nearly enough for anyone to be able to give you a good answer at this point, without a lot of guesswork. – M. Eriksson Jul 17 '17 at 13:28
  • @RiggsFolly, no it's not a scope issue. The problem is that there are a lot of foreach-es that add up some numbers to an array which is undefined (+=) – Miro Xristov Jul 17 '17 at 13:28
  • @ArturKäpp, thank you. I will try this an come back with an answer. – Miro Xristov Jul 17 '17 at 13:30
  • you can try using set_error_handler('exceptions_error_handler'), and put your code in try { } catch() {} - like here https://stackoverflow.com/questions/5373780/how-to-catch-this-error-notice-undefined-offset-0 – Bogdan Mantescu Jul 17 '17 at 13:31
  • @MagnusEriksson, yes you're right. I avoided this step because there is a lot of code, but I will edit my question and add one of the many foreach-es where these arrays are generated: – Miro Xristov Jul 17 '17 at 13:35
  • If it does not exists now, then one assumes it did not exists when the code was proceedural. – RiggsFolly Jul 17 '17 at 13:42
  • @RiggsFolly, yes your assumption is right. But in plain php it works. It's a bad practice, but I can't rewrite the entire business logic on a big, old project, written by someone else, just in a day. – Miro Xristov Jul 17 '17 at 13:46
  • Tell whoever, the code is bad, you need longer – RiggsFolly Jul 17 '17 at 13:48
  • @MagnusEriksson, I've edited my question adding some code at the bottom. Also want to thank all of you for the quick reactions. I really appretiate that – Miro Xristov Jul 17 '17 at 13:52
  • why would you not want the ifs? For fewer lines? You can't 100% gurantee every field to have a value, especially if regex is only applicable to say X/Y fields (where Y is bigger than X) - if you really want you could foreach loop it and add a check inside that sets a bool value and then if statement that – treyBake Jul 17 '17 at 14:19
  • @ThisGuyHasTwoThumbs, I want to avoid them, because I have to write more than 250 if s (for each array). Something inside me tells, that this is very bad :) And I think this will affect performance. – Miro Xristov Jul 17 '17 at 14:28
  • @MiroXristov you can use switch statements to shorten line - or like I said, just write a foreach statement and check that - in fact I'll post an answer :) – treyBake Jul 17 '17 at 14:28
  • @ArturKäpp, thank you for pointing these functions out, they seem to be very useful, but not in my case. For instance I can't use them on this: $profiles[$month][$class] += round($energy * $energy_factor[$class], 3) . See the code at the end of my question ;) – Miro Xristov Jul 18 '17 at 07:03

2 Answers2

2

Try doing this:

https://stackoverflow.com/a/39642147/1921979

My best guess: the issue isn't that laravel is throwing errors, or that plain PHP was okay with this code before. Rather your environment has changed. Your application has always generated notices but your previous environment was configured to ignore them. Laravel is (correctly) configured to treat notices as errors. The above link should change the error reporting in laravel to also ignore notices. However: if that works you shouldn't leave notices off altogether. Rather, you should call error_reporting() before your legacy code runs to disable reporting of notices, and then you should call error_reporting() again right afterwards to turn reporting of notices back on. For background:

Laravel's behavior is a good thing. A production application should generate neither errors nor notices. While you could ignore notices, that doesn't mean it is a good idea. They are frequently the result of bugs that are causing problems but not otherwise raising errors (for instance, a typo in a variable name). So the root of your problem isn't that laravel is reporting notices, but that whoever wrote your legacy application ignored notices and wrote error-prone code. In this case the notices are likely a sign of sloppy coding more than actual bugs, so turning off notices may be a viable solution here. However, the last thing you want to do is to just turn off notices all together and turn your new application into another soon-to-be-legacy-application-that-can't-be-run-in-a-modern-environment-due-to-notices. So if you disable error reporting for notices, don't do it throughout your app: just do it for the legacy stuff.

Conor Mancone
  • 1,940
  • 16
  • 22
  • Thank you for this well constructed answer. – Miro Xristov Jul 17 '17 at 14:43
  • I want to thank you one more time for reading my question carefully and getting quick inside the topic. You saved my ass. I know that this is a quick fix (hack), but it fits perfect for the situation I am in. Thank you – Miro Xristov Jul 18 '17 at 07:56
1

To shorten isset checks you can do:

$array = ['keyOne' => 'test', 'keyThree' => 'testing'];
$data  = [];

foreach ($array as $key => $value)
{
    if (isset($array[$key]) {
        $data[$key] = $value;
    }
}

var_dump($data); //this will display the orig value because there is 
                 //nothing set - but in your code I'm sure it will strip
                 //out not-set data

what this does, is foreach an array, test the $key against the original array and if it's set, it adds it to a $data array to use for SQL etc..

treyBake
  • 6,440
  • 6
  • 26
  • 57
  • nice idea. Thank you :) – Miro Xristov Jul 17 '17 at 14:44
  • @MiroXristov no worries :) happy to help – treyBake Jul 17 '17 at 14:47
  • @ThisGuyHasTwoThumbs This is actually just a long way of saying: `$data = array_merge( $data, $array )`. In both cases though there is one important caveat: it won't work well for multi-dimensional arrays, which the OP has lots of. – Conor Mancone Jul 17 '17 at 16:40
  • @ConorMancone ah didn't know that! Productivity stats +1 haha thanks! :) and that is true. This will only work on single level arrays. Will edit tomorrow morning with something for multis as on phone for the eve. – treyBake Jul 17 '17 at 18:01
  • @ThisGuyHasTwoThumbs yeah, multi-dimensional arrays can cause a lot of trouble (although I still use them plenty myself). I've always secretly longed for a multi-dimension friendly `array_merge` function. – Conor Mancone Jul 17 '17 at 18:06
  • @ThisGuyHasTwoThumbs It's also funny how you can miss out on some simple functions for a long time. It was about a decade before I finally learned about the `empty` function, and that simplified a whole lot of `if ( !isset( $array['value'] ) || !$array['value'] )` conditionals for me. I could have used that one a long time ago... lol! – Conor Mancone Jul 17 '17 at 18:18
  • @ConorMancone yeah haha multis can be tricky to work with hhha :) and haha yeah it's weird what goes under the radar, I too remember not finding empty for a good while haha – treyBake Jul 18 '17 at 08:33