PHP function written in 5.5 throws error when upgraded to 7.0 - syntax-error

here is the function that worked prior to upgrading to 7.0
function set_session_vars() {
$nb_args=func_num_args();
$arg_list=func_get_args();
for($i=0;$i<$nb_args;$i++) {
global $$arg_list[$i];
$_SESSION[$arg_list[$i]] = $$arg_list[$i];
}
}
now it causer error that says:
Parse error: syntax error, unexpected '[', expecting ',' or ';' in /home/mvyc1956/public_html/members/includes/functions.php on line 322
I believe its related to non backward compatable changes to GLOBAL and the use of $$ and arrays, but my PHP is not good enough to figure it out.
Is there someone who is familiar with why this line :
global $$arg_list[$i];
which is line 322 that is being reported as the cause of the error, would be failing now, and what would you recommend I change the code to in order to have it work with PHP 7?
I did some googling and found this page but again, im not understanding what needs to be changed.
thanks
says syntax error so some of the code in the function is no longer valid, but it would take a php 7 expert to see it.
UPDATE
I removed the word GLOBAL from the above code and the app "seems" to be now working fine so I will now ask:
Does anyone know specifically, why Global was the non compatibility issue? and is my fix of simply removing it a solid one or will is there a better practice or will this removal come back to haunt me?

Backward incompatible changes:
global only accepts simple variables
Variable variables can no longer be used with the global keyword. The curly brace syntax can be used to emulate the previous behaviour if required:
// Valid in PHP 5 only.
global $$foo->bar;
// Valid in PHP 5 and 7.
global ${$foo->bar};
So in your case it should become:
global ${$arg_list[$i]};

The global keyword tells PHP to access a global variable (per launch of the script) instead of a local variable (per function). For example,
global $foo;
means that future uses of the variable $foo in that function refer to the global variable with that name, rather than a variable within the function itself.
What this is trying to do is look up a variable by arbitrary name in the global namespace. That's entirely the wrong way to do things. Instead, you should have a global array and use keys in the array. In fact, $$ is arguably a bad idea in general.
But that's neither here nor there. The problem is that the parsing rules changed in PHP 7.0 in a non-backwards-compatible way (because they're using a more traditional parser now, and thus had to make their associativity rules self-consistent).
More details here:
http://php.net/manual/en/migration70.incompatible.php#migration70.incompatible.variable-handling.indirect
To make a long story short, you need to rewrite that as:
global ${$arg_list[$i]};
and then your code will work correctly on both PHP 7 and PHP 5.
Incidentally, the function only appears to work without the global keyword. In fact, it is always getting empty values for those variables.

Related

How can one invoke the non-extension `run` function (the one without scope / "object reference") in environments where there is an object scope?

Example:
data class T(val flag: Boolean) {
constructor(n: Int) : this(run {
// Some computation here...
<Boolean result>
})
}
In this example, the custom constructor needs to run some computation in order to determine which value to pass to the primary constructor, but the compiler does not accept the run, citing Cannot access 'run' before superclass constructor has been called, which, if I understand correctly, means instead of interpreting it as the non-extension run (the variant with no object reference in https://kotlinlang.org/docs/reference/scope-functions.html#function-selection), it construes it as a call to this.run (the variant with an object reference in the above table) - which is invalid as the object has not completely instantiated yet.
What can I do in order to let the compiler know I mean the run function which is not an extension method and doesn't take a scope?
Clarification: I am interested in an answer to the question as asked, not in a workaround.
I can think of several workarounds - ways to rewrite this code in a way that works as intended without calling run: extracting the code to a function; rewriting it as a (possibly highly nested) let expression; removing the run and invoking the lambda (with () after it) instead (funnily enough, IntelliJ IDEA tags that as Redundant lambda creation and suggests to Inline the body, which reinstates the non-compiling run). But the question is not how to rewrite this without using run - it's how to make run work in this context.
A good answer should do one of the following things:
Explain how to instruct the compiler to call a function rather than an extension method when a name is overloaded, in general; or
Explain how to do that specifically for run; or
Explain that (and ideally also why) it is not possible to do (ideally with supporting references); or
Explain what I got wrong, in case I got something wrong and the whole question is irrelevant (e.g. if my analysis is incorrect, and the problem is something other than the compiler construing the call to run as this.run).
If someone has a neat workaround not mentioned above they're welcome to post it in a comment - not as an answer.
In case it matters: I'm using multi-platform Kotlin 1.4.20.
Kotlin favors the receiver overload if it is in scope. The solution is to use the fully qualified name of the non-receiver function:
kotlin.run { //...
The specification is explained here.
Another option when the overloads are not in the same package is to use import renaming, but that won't work in this case since both run functions are in the same package.

What is indirect object notation, why is it bad, and how does one avoid it?

The title pretty much sums it up, but here's the long version anyway.
After posting a small snippet of perl code, I was told to avoid indirect object notation, "as it has several side effects". The comment referenced this particular line:
my $some_object = new Some::Module(FIELD => 'value');
As this is how I've always done it, in an effort to get with the times I therefore ask:
What's so bad about it? (specifically)
What are the potential (presumably negative) side effects?
How should that line be rewritten?
I was about to ask the commenter, but to me this is worthy of its own post.
The main problem is that it's ambiguous. Does
my $some_object = new Some::Module(FIELD => 'value');
mean to call the new method in the Some::Module package, or does it mean to call the new function in the current package with the result of calling the Module function in the Some package with the given parameters?
i.e, it could be parsed as:
# method call
my $some_object = Some::Module->new(FIELD => 'value');
# or function call
my $some_object = new(Some::Module(FIELD => 'value'));
The alternative is to use the explicit method call notation Some::Module->new(...).
Normally, the parser guesses correctly, but the best practice is to avoid the ambiguity.
What's so bad about it?
The problems with Indirect Method Notation are avoidable, but it's far easier to tell people to avoid Indirect Method Notation.
The main problem it's very easy to call the wrong function by accident. Take the following code, for example:
package Widget;
sub new { ... }
sub foo { ... }
sub bar { ... }
sub method {
...;
my $o = new SubWidget;
...;
}
1;
In that code, new SubWidget is expected to mean
SubWidget->new()
Instead, it actually means
new("SubWidget")
That said, using strict will catch most of these instances of this error. Were use strict; to be added to the above snippet, the following error would be produced:
Bareword "SubWidget" not allowed while "strict subs" in use at Widget.pm line 11.
That said, there are cases where using strict would not catch the error. They primarily involve the use of parens around the arguments of the method call (e.g. new SubWidget($x)).
So that means
Using Indirect Object Notation without parens can result in odd error messages.
Using Indirect Object Notation with parens can result in the wrong code being called.
The former is bearable, and the latter is avoidable. But rather than telling people "avoid using parens around the arguments of method calls using Indirect Method Notation", we simply tell people "avoid using Indirect Method Notation". It's just too fragile.
There's another issue. It's not just using Indirect Object Notation that's a problem, it's supporting it in Perl. The existence of the feature causes multiple problems. Primarily,
It causes some syntax errors to result in very odd/misleading error messages because the code appeared to be using ION when it wasn't.
It prevents useful features from being implemented since they clash with valid ION syntax.
On the plus side, using no indirect; helps the first problem.
How should that line be rewritten?
The correct way to write the method call is the following:
my $some_object = Some::Module->new(FIELD => 'value');
That said, even this syntax is ambiguous. It will first check if a function named Some::Module exists. But that's so very unlikely that very few people protect themselves from such problems. If you wanted to protect yourself, you could use the following:
my $some_object = Some::Module::->new(FIELD => 'value');
As to how to avoid it: There's a CPAN module that forbids the notation, acting like a pragma module:
no indirect;
http://metacpan.org/pod/indirect
The commenter just wanted to see Some::Module->new(FIELD => 'value'); as the constructor.
Perl can use indirect object syntax for other bare words that look like they might be methods, but nowadays the perlobj documentation suggests not to use it.
The general problem with it is that code written this way is ambiguous and exercises Perl's parser to test the namespace to e.g. check when you write method Namespace whether Namespace::method exists.

Variable Encapsulation in Case Statement

While modifying an existing program's CASE statement, I had to add a second block where some logic is repeated to set NetWeaver portal settings. This is done by setting values in a local variable, then assigning that variable to a Changing parameter. I copied over the code and did a Pretty Print, expecting to compiler to complain about the unknown variable. To my surprise however, this code actually compiles just fine:
CASE i_actionid.
WHEN 'DOMIGO'.
DATA: ls_portal_actions TYPE powl_follow_up_sty.
CLEAR ls_portal_actions.
ls_portal_actions-bo_system = 'SAP_ECC_Common'.
" [...]
c_portal_actions = ls_portal_actions.
WHEN 'EBELN'.
ls_portal_actions-bo_system = 'SAP_ECC_Common'.
" [...]
C_PORTAL_ACTIONS = ls_portal_actions.
ENDCASE.
As I have seen in every other programming language, the DATA: declaration in the first WHEN statement should be encapsulated and available only inside that switch block. Does SAP ignore this encapsulation to make that value available in the entire CASE statement? Is this documented anywhere?
Note that this code compiles just fine and double-clicking the local variable in the second switch takes me to the data declaration in the first. I have however not been able to test that this code executes properly as our testing environment is down.
In short you cannot do this. You will have the following scopes in an abap program within which to declare variables (from local to global):
Form routine: all variables between FORM and ENDFORM
Method: all variables between METHOD and ENDMETHOD
Class - all variables between CLASS and ENDCLASS but only in the CLASS DEFINITION section
Function module: all variables between FUNCTION and ENDFUNCTION
Program/global - anything not in one of the above is global in the current program including variables in PBO and PAI modules
Having the ability to define variables locally in a for loop or if is really useful but unfortunately not possible in ABAP. The closest you will come to publicly available documentation on this is on help.sap.com: Local Data in the Subroutine
As for the compile process do not assume that ABAP will optimize out any variables you do not use it won't, use the code inspector to find and remove them yourself. Since ABAP works the way it does I personally define all my variables at the start of a modularization unit and not inline with other code and have gone so far as to modify the pretty printer to move any inline definitions to the top of the current scope.
Your assumption that a CASE statement defines its own scope of variables in ABAP is simply wrong (and would be wrong for a number of other programming languages as well). It's a bad idea to litter your code with variable declarations because that makes it awfully hard to read and to maintain, but it is possible. The DATA statements - as well as many other declarative statements - are only evaluated at compile time and are completely ignored at runtime. You can find more information about the scopes in the online documentation.
The inline variable declarations are now possible with the newest version of SAP Netweaver. Here is the link to the documentation DATA - inline declaration. Here are also some guidelines of a good and bad usage of this new feature
Here is a quote from this site:
A declaration expression with the declaration operator DATA declares a variable var used as an operand in the current writer position. The declared variable is visible statically in the program from DATA(var) and is valid in the current context. The declaration is made when the program is compiled, regardless of whether the statement is actually executed.
Personally have not had time to check it out yet, because of lack of access to such system.

Within CPPUNIT_ASSERT, Keep Getting Access Violation

I have a set of classes to which I am trying to apply unit tests, to maintain their current utility through future revisions.
My problem is that within CPPUNIT, to which I am new, where-ever I call CPPUNIT_ASSERT ( [condition] ), I am met with Error Unhandled Exception...: Access Violation at 0xffffffffffffffff.
This happens even I write the simplest test case
int main(){
CPPUNIT_ASSERT ( true );
}
I have tried calling my testing functions with manual calls, as well as adding them to a registry, as is done in the Money example. The problem reportedly arises within the constructor for SourceLine, as the filename string it expects is a bad pointer.
After a bit of a search I've found that this is called within the CPPUNIT_ASSERT, as it's a macro with the following definition
#define CPPUNIT_ASSERT(condition) \
( CPPUNIT_NS::Asserter::failIf( !(condition), \
CPPUNIT_NS::Message( "assertion failed", \
"Expression: " #condition), \
CPPUNIT_SOURCELINE() ) )
I've searched the tutorials on CppUnit's site, and scrutinised stackoverflow, but I have not found anything that addresses this in particular. I do find it strange that what is, in every example I've seen, a single-parameter function (assert), will call another function with no arguments (sourceline) that is actually another macro that is assuming it receives a string, but can receive no such thing. I found that SourceLine is a class that still has a default constructor, but above is called a macro, which really refers to the 2-parameter constructor, but is passed no arguments that I can see. I am at a loss.
I am using a 64 bit compilation of CppUnit, verified with a dumpbin, and Visual Studio 2008.
Cppunit's assertion system uses macros so it is expected that your simple example complains about unhandled exception.
Normally you don't use an assertion outside of a test method. I suggest you have a look at the Cppunit Cookbook which provides some information and examples how to effectively use cppunit.

Single line exception to GCC_WARN_SHADOW = YES?

I have this code:
id error;
// a bunch of stuff, including using error
Finalization finalization = ^(int status) {
id error; // <--- Declaration shadows a local variable
// a bunch of stuff, using error
}
// a bunch of stuff, using error
I use GCC_WARN_SHADOW because it's what I want in every case in my code except this one. In this case, it gives me a warning that I want to suppress.
Is there a way to suppress this one shadow warning without turning off GCC_WARN_SHADOW or renaming the inner error to something else? Some way to mark that declaration of error?
I'm using clang with Xcode 4, if it matters.
First, as a matter of opinion, it's really bad karma to shadow a local variable within an inner block (its bad enough shadowing a global variable in a function). Now "error" can take two different values within a function, and until whomever is reading your code figures it out, they will bang their head quite incessantly. I have seen this issue in real life among paid professionals developing apps. I really suggest renaming the inner error variable.
Answering your question, you can use the GCC/clang compiler pragma to suppress a warning.