PHP 5 code not working in PHP 4 - php

I have this function in PHP 5:
function myPHPFunction($shows) {
foreach($shows as &$show) {
$showData = $this->Api->getID(null, $show->showId, false);
$show->Id = $showData->Id;
}
return $shows;
}
the $shows array has empty id, I am able to get the id with an Api call and when I return $shows at the end, the id field is populated. If I move this code to PHP 4:
function myPHPFunction($shows) {
foreach($shows as $show) {
$showData = $this->Api->getID(null, $show->showId, false);
$show->Id = $showData->Id;
}
return $shows;
}
The $shows array still has an empty id field when I return is. Does it have something to with &$ because the & does not work in PHP 4

Yes pass by reference was available only after PHP 4.0.4
There is no reference sign on a function call - only on function
definitions. Function definitions alone are enough to correctly pass
the argument by reference. As of PHP 5.3.0, you will get a warning
saying that "call-time pass-by-reference" is deprecated when you use &
in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was
removed, so using it will raise a fatal error.
Source

Related

I get this error "Function name must be a string"

I have a PHP class where one of the private member is a callback to my log function (i.e. in PHP land, a function pointer is simply a string containing the name of the function to call).
self::$logferr = "msgfunc";
self::$logferr($res);
I get this error:
Fatal error: Function name must be a string
self::$logferr is equal to "msgfunc" which is my log function.
If I rewrite the code like this (on the same very class method):
$tmp = "msgfunc";
$tmp($res);
It works, the log function get called
Just wrap your variable in parenthesis, let PHP resolve the value first:
(self::$logferr)($res);
Proof of concept
You can use call_user_func. ref: this
call_user_func(self::$logferr, $res);
You should call it by using
self::{self::$logferr}($req)
Working example : https://3v4l.org/CYURS
Let's build a reproducible example:
class Foo {
private static $_loggerCallback;
static function setLogCallback(callable $loggerCallback) {
self::$_loggerCallback = $loggerCallback;
}
static function log(...$arguments) {
if (NULL !== self::$_loggerCallback) {
return self::$_loggerCallback(...$arguments);
}
return NULL;
}
}
Foo::setLogCallback(function() { echo 'success'; } );
Foo::log();
Output:
Notice: Undefined variable: _loggerCallback in /in/f3stL on line 13
Fatal error: Uncaught Error: Function name must be a string in /in/f3stL:13
The notice reports the actual mistake in this case. If you do not get something like it, you should check your error reporting configuration.
The notice shows that PHP looks for a local variable $_loggerCallback. It tries to execute $_loggerCallback(...$arguments). Here are different possibilities to make the call explicit.
Use parenthesis (PHP >= 7.0):
return (self::$_loggerCallback)(...$arguments);
Use a local variable (as you did):
$callback = self::$_loggerCallback;
return $callback(...$arguments);
A small advise. PHP support anonymous functions. You do not need a (global) function for a callback. This avoids calling to the function by name as well.

PHP 7 Execute object method as array element

I am a bit stuck with question why in PHP 7 dropped functionality of accesing object methods using array elements as method name.
E.g.:
$carObj = new Car();
$array = ['method'=>'getMilage', 'object'=>$carObj];
// FATAL HERE:
$mileage = $array['object']->$array['method']();
// WORKS OK:
$objName = $array['object'];
$metName = $array['method'];
$mileage = $objName->$metName();
This code works on PHP 5.6 for sure, however when switched to PHP 7.1 it throws now fatal. Failed to find anything re this in release notes and SO topics.
P.S. Originally found this in Magento 1.14.2.0 version upon PHP upgrade, as Varien library uses this code:
File: Varien/File/Uploader.php
//run validate callbacks
foreach ($this->_validateCallbacks as $params) {
if (is_object($params['object']) && method_exists($params['object'], $params['method'])) {
$params['object']->$params['method']($this->_file['tmp_name']);
}
}
Gives this:
Fatal error: Uncaught Error: Function name must be a string in
/var/www/html/lib/Varien/File/Uploader.php on line 274
--
EDIT #1:
You can TEST it here:
http://sandbox.onlinephpfunctions.com/code/d1d2d36f96a1b66ed7d740db328cd1f14cc2d7d8
(Note: I'm assuming the 'object'=>'carObj' declaration is supposed to be 'object'=>$carObj here - there's no way this code works in any version of PHP otherwise.)
The clue is in the Notice: Array to string conversion in... notice raised before the fatal error.
In PHP 5, the following statement:
$array['object']->$array['method']();
is evaluated like this:
$array['object']->{$array['method']}();
where $array['method'] is evaluated before calling it on the object.
In PHP 7, it's evaluated like this
($array['object']->$array)['method']();
where the $array property is looked up on the object first. Since it doesn't exist (obviously, since it's an array), a notice is thrown, and then a subsequent fatal error when the method itself can't be called.
If you want to preserve the PHP 5 behaviour, wrap some {} around the method name lookup:
$carObj = new Car();
$array = ['method'=>'getMilage', 'object'=>$carObj];
$mileage = $array['object']->{$array['method']}();
See https://3v4l.org/Is5lX
This is explained in a bit more detail here: http://php.net/manual/en/migration70.incompatible.php
Your code works for sure not in PHP5.6
The content of $array['object'] is an string and using the -> member operator on an string always throws an error
Call to a member function getMilage() on string in [...][...] on line [...]
The only way to get this to work is resolve the var with $ or - even better store the object inside the array and not simply the var.
$mileage = ${$array['object']}->$array['method']();
better solution
$array = ['method' => 'getMilage', 'object' => $carObj];
$mileage = $array['object']->{$array['method']}();
Sidenote: in php7 they changed the evaluation order in case of ambiguities - so you have to add explicitly {} around $array['method']. To prevent this, one would normaly extract first the object and method and then simply call it without the array dereferencing.
Btw. the Magento Varien code you posted also expects $params['object'] to be an array. There is even a is_object test to ensure, you couldn't pass just var names.
//run validate callbacks - even in php7
foreach ($this->_validateCallbacks as $params) {
if (is_object($params['object']) && method_exists($params['object'], $params['method'])) {
$object = $params['object'];
$method = $params['method'];
$object->$method($this->_file['tmp_name']);
}
}
You must add $ before the object variable
$carObj = new Car();
$array = ['method'=>'getMilage', 'object'=>'carObj'];
$object = $array['object'];
$method = $array['method'];
// FATAL HERE:
$mileage = $$object->$method();
// WORKS OK:
$objName = $array['object'];
$metName = $array['method'];
$mileage = $$objName->$metName();

attempt to use array_map in a class is resulting in a warning

A new class has been created for a PHP project as follows:
class Cleanse
{
# trims leading and trailing spaces
public static function trimmer($values)
{
return is_array($values) ?
array_map('trimmer', $values) :
trim($values);
}
}
However, when trying to use this functionality like so:
$values = Cleanse::trimmer($_POST);
the following warning message is returned:
Warning: array_map() expects parameter 1 to be a valid callback, function 'trimmer' not found or invalid function name in (class file path) on line 41.
What is wrong with this code and/or this approach?
As trimmer is a static method of Cleanse, it should be
array_map('Cleanse::trimmer', $values) // PHP >= 5.2.3
or
array_map(array('Cleanse', 'trimmer'), $values) // PHP < 5.2.3
See Callbacks for the correct syntax to use for callbacks.

php version upgrade cause an error for old program

I just installed xampp, to run some old program (created 2 or more years ago) and I'm getting 3 errors I can't figure out.
Strict Standards: Only variables should be passed by reference in C:\xampp\htdocs\2010\web\core\route\route.php on line 117
public function loadClass($address,$ext='') {
$this->extname = preg_replace('/_/','/',$address,3);
line:117> $this->classname = end(explode('_',$address)).($e= $ext!='' ? '('.$ext.')' : '');
include_once(ROOT_ROUTE.'/'.$this->extname.'.php');
$this->newclass = new $this->classname;
return $this->newclass;
}
the line 117 i can't understand, it is not using passed by reference, why there is a error?
Because end() expects an argument passed by reference, you can't use it with a non-variable such as the direct result of another function call or construct.
Quoting from the argument definition in the manual:
This means you must pass it a real variable and not a function returning an array because only actual variables may be passed by reference.
Change
$this->classname = end(explode('_',$address)).($e= $ext!='' ? '('.$ext.')' : '');
to
$addressTemp = explode('_',$address);
$this->classname = end($addressTemp) . ($e= $ext!='' ? '('.$ext.')' : '');

PHP: Array passed by reference to a function?

I have this php function that has to perform some processing on a given array:
processArray($arrayToProcess) {
$arrayToProcess['helloStackOverflow'] = TRUE;
}
Later, the code invokes the following:
$niceArray = array('key' => 'value');
processArray($niceArray);
The key 'helloStackOverflow' isn't available outside the processArray function. I tried calling the following:
processArray(&$niceArray);
Using "&" helps, however it raises some warning:
Deprecated function: Call-time pass-by-reference has been deprecated; If you would like to pass it by reference, modify the declaration of populateForm_withTextfields()
Tried the & in there, but that just stops the code.
How should I do this?
You have to define the reference in the function, not in the call to the function.
function processArray(&$arrayToProcess) {
processArray(&$arrayToProcess) {
$arrayToProcess['helloStackOverflow'] = TRUE;
}
implements the reference in PHP way.
See http://fi2.php.net/references for useful information about references.
processArray(&$arrayToProcess) {
$arrayToProcess['helloStackOverflow'] = TRUE;
}
Referencing passing now takes place at the function declaration, not when the function is called.
http://php.net/manual/en/language.references.pass.php
for full documentation.

Categories