PHP 5.3 $this versus PHP 5.4 [duplicate] - php

This question already has answers here:
call_user_func within class context (with $this defined)
(4 answers)
Closed 10 years ago.
I am calling a member function inside an anonymous function using $this.
$this->exists($str)
PHP 5.4 does not give me problems, 5.3 gives me problems.
The error is
<b>Fatal error</b>: Using $this when not in object context in
Here is my code
class WordProcessor
{
private function exists($str)
{
//Check if word exists in DB, return TRUE or FALSE
return bool;
}
private function mu_mal($str)
{
if(preg_match("/\b(mu)(\w+)\b/i", $str))
{ $your_regex = array("/\b(mu)(\w+)\b/i" => "");
foreach ($your_regex as $key => $value)
$str = preg_replace_callback($key,function($matches)use($value)
{
if($this->exists($matches[0])) //No problems in PHP 5.4, not working in 5.3
return $matches[0];
if($this->exists($matches[2]))
return $matches[1]." ".$matches[2];
return $matches[0];
}, $str);
}
return $str;
}
}

You're using $this inside of a closure which is executed in a separate context.
At the beginning of your mu_mal function, you should declare $that = $this (or something like $wordProcessor to be more explicit about what the variable is). Then, inside of your preg_replace_callback's closure, you should add use ($that) and reference $that inside of your closure instead of $this.
class WordProcessor
{
public function exists($str)
{
//Check if word exists in DB, return TRUE or FALSE
return bool;
}
private function mu_mal($str)
{
$that = $this;
if(preg_match("/\b(mu)(\w+)\b/i", $str))
{
$your_regex = array("/\b(mu)(\w+)\b/i" => "");
foreach ($your_regex as $key => $value)
$str = preg_replace_callback($key,function($matches)use($value, $that)
{
if($that->exists($matches[0])) //No problems in PHP 5.4, not working in 5.3
return $matches[0];
if($that->exists($matches[2]))
return $matches[1]." ".$matches[2];
return $matches[0];
}, $str);
}
return $str;
}
}
Note that you have to expose exists to the public API of the class (which I have done above)
This behavior was changed in PHP 5.4

Related

How to Convert a Function into a Closure in PHP?

I have function that uploads files to server:
function upload() {
$files = Input::file(self::$filename);
foreach ($files as $key => $file) {
// Validation
// Uploading
}
}
So, how to make this function as closure? That after loading it returns error or success information to output variable:
$results = function upload() {
}
In results should be result array of uploading files. It can be error or success state.
Since you're using self:: I assume you expect to run this function from inside a class. But you can't really do this - the function should be defined in the class to be able to use self::.
But really, you can just pass it as a parameter.
function upload($filename) {
$files = Input::file($filename); // note, self:: removed
foreach ($files as $key => $file) {
// Validation
// Uploading
}
return $result;
}
And when you need to use it inside your class, call it this way:
$result = upload(self::$filename);
For Converting a Function into a Closure in PHP, you can :
Since PHP 7 >= 7.1.0, you can use Closure::fromCallable()
$cl = Closure::fromCallable("upload");
$result = $cl();
Before (PHP >= 5.4.0), you can use ReflectionFunction::getClosure()
$reflexion = new ReflectionFunction('upload');
$cl = $reflexion->getClosure();
$result = $cl();
Another idea is to construct a new function that call your main function :
$cl = function (...$args) {
return upload(...$args);
};
Updated and Expanded
This answer addresses the OP's primary question of "How to Convert a Function into a Closure in PHP?" One way involves writing a nameless function and then assigning it to a variable. Since the OP's upload code is problematic, i.e. a method without a class, I therefore borrow the corrected code of #astax, modifying it for the purpose of illustrating the mechanics of how to create a closure in PHP, as follows:
<?php
$f = function( $filename ) {
$files = Input::file( $filename );
foreach ($files as $key => $file) {
// Validation
// Uploading
}
return $arrResults;
};
Note the trailing semicolon after the final brace. Also, the closure definition consists of an anonymous function. You may get the result as follows:
<?php
$arrResults = $f( $filename );
// or in a class:
$arrResults = $f( self::$filename );
Note: PHP does not have named closures, so the function needs to be anonymous. Usually it is assigned to a variable but PHP 7 provides more flexibility such that you may avoid setting a variable as the following two basic examples indicate:
<?php
echo (function() {
return 2 * 2;
})(),"\n",
(function(){
return function(){
return 3 * 3;
};
})()();
See live code.
This syntax is possible thanks to the support for function call chaining in PHP 7.
Note: if your code includes a return statement, when the closure executes, you may assign the return value to a variable.
Incidentally, two useful articles on PHP's closures: see this issue as well in this issue.
Lastly, note while other languages recognize a bound variable with a function as a closure and a nameless function as an anonymous function, in PHP support for each is done vis a vis the Closure class.
Caveat:
Care should be taken when creating a closure from the Closure object's fromCallable method since it evidently yields a more restricted closure as the following code demonstrates:
<?php
class A {
private $name;
public function __construct($name)
{
$this->name = $name;
}
}
$person = new A("Tim");
function test() {
return $this->name;
}
$f = function() {
return $this->name;
};
$cl = Closure::fromCallable( $f );
echo $cl->bindTo($person, 'A')();
echo "\n\nBut, Closure::fromCallable problematic:\n";
try {
$cl = Closure::fromCallable( "test" );
echo $cl->bindTo($person, 'A')();
} catch (Error $e) {
echo "Unable to bind closure from callable because: \n";
echo $e->getMessage();
}
see live code
The error message that results is as follows:
Warning: Cannot rebind scope of closure created by
ReflectionFunctionAbstract::getClosure() in /in/qso7b on line 26
Unable to bind closure from callable because: Function name must be a
string

PHP - Can you assign a member function to a variable? [duplicate]

This question already has answers here:
php call class function by string name
(6 answers)
Closed 8 years ago.
In PHP5, variables can be evaluated as functions1 such as:
function myFunc() {
echo "whatever";
}
$callableFunction = 'myFunc';
$callableFunction(); // executes myFunc()
Is there any syntax for assigning object member functions to a variable such as:
class MyClass {
function someCall() {
echo "yay";
}
}
$class = new MyClass();
// what I would like:
$assignedFunction = $class->someCall; // but I tried and it returns an error
$memberFunc = 'someCall';
$class->$memberFunc(); // I know this is valid, but I want a single variable to be able to be used to call different functions - I don't want to have to know whether it is part of a class or not.
// my current implementation because I don't know how to do it with anonymous functions:
$assignedFunction = function() { return $class->someCall(); } // <- seems lengthy; would be more efficient if I can just assign $class->someCall to the variable somehow?
$assignedFunction(); // I would like this to execute $class->someCall()
There is a way, but for php 5.4 and above...
class MyClass {
function someCall() {
echo "yay";
}
}
$obj = new Myclass();
$ref = array($obj, 'someCall');
$ref();
Hm.. actually it works for static too, just use the reference by name..
class MyClass {
static function someCall2() {
echo "yay2";
}
}
$ref = array('MyClass', 'someCall2');
$ref();
And for nonstatic this notation works as well. It creates a temporary instance of the class. So, this is what you need, only you need php 5.4 and above )
The PHP 5.4 solution above is good. If you need PHP 5.3, I don't think you can do much better than the anonymous function approach, but you could wrap that into a function that acts very similar to the PHP 5.4 method:
function buildCallable($obj, $function)
{
return function () use ($obj, $function) {
$args = func_get_args();
return call_user_func_array(array($obj, $function), $args);
};
}
//example
class MyClass
{
public function add($x, $y)
{
return $x + $y;
}
public static function multiply($x, $y)
{
return $x * $y;
}
}
//non-static methods
$callable = buildCallable(new MyClass(), 'add');
echo $callable(32, 10);
//static methods
$callable = buildCallable('MyClass', 'multiply');
echo $callable(21, 2);
This should work for any number of arguments to any (publicly visible) method.

php call another function in a function [duplicate]

This question already has answers here:
Fatal error: Using $this when not in object context
(4 answers)
Closed 8 years ago.
im trying to call a function inside another function. based on some research they say using
$this->
should work. but it gave me
Fatal error: Using $this when not in object context
function addstring($input, $addition_string , $position) {
$output = substr_replace($input, $addition_string, $position, 0);
return $output;
}
function test($astring) {
$output2 = $this->addstring($astring, 'asd', 1);
}
to view the rest of my code :
http://pastebin.com/5ukmpYVB
error :
Fatal error: Using $this when not in object context in BLA.php on line 48
$this-> is needed if you are within a class, if you don't, just call the function by its name:
function test($astring) {
$output2 = addstring($astring, 'asd', 1);
}
Besides the error mentioned by Nicolas,
function test($astring) {
has no return value and does not use the parameter by reference, which means, the function is not doing anything but wasting performance.
To demonstrate how you bring the functions into class context:
class StringHelper
{
private $output;
protected function addstring($input, $addition_string , $position) {
$output = substr_replace($input, $addition_string, $position, 0);
return $output;
}
public function test($astring) {
$this->output = $this->addstring($astring, 'asd', 1);
return $this;
}
public function getOutput() {
return $this->output;
}
}
$stringObj = new StringHelper;
echo $stringObj->test('my string')->getOutput();

invoking runtime created functions

I'm trying to dynamically create the base for a DB entity generalization for a project I'm working on. I basically want to dynamically create a set of standard methods and tools for the properties in any class that extends this. Much like the tools you get for free with Python/Django.
I got the idea from this guy: http://www.stubbles.org/archives/65-Extending-objects-with-new-methods-at-runtime.html
So I've implemented the __call function as described in the post above,
public function __call($method, $args) {
echo "<br>Calling ".$method;
if (isset($this->$method) === true) {
$func = $this->$method;
$func();
}
}
I have a function which gives me the objects public/protected properties through get_object_vars,
public function getJsonData() {
$var = get_object_vars($this);
foreach($var as &$value) {
if (is_object($value) && method_exists($value, 'getJsonData')) {
$value = $value->getJsonData;
}
}
return $var;
}
and now I want to create some methods for them:
public function __construct() {
foreach($this->getJsonData() as $name => $value) {
// Create standard getter
$methodName = "get".$name;
$me = $this;
$this->$methodName = function() use ($me, $methodName, $name) {
echo "<br>".$methodName." is called";
return $me->$name;
};
}
}
Thanks to Louis H. which pointed out the "use" keyword for this down below.
This basically creates an anonymous function on the fly. The function is callable, but it is no longer within the context of it's object. It produces a "Fatal error: Cannot access protected property"
Unfortunately I'm bound to PHP version 5.3, which rules out Closure::bind. The suggested solution in Lazy loading class methods in PHP will therefore not work here.
I'm rather stumped here... Any other suggestions?
Update
Edited for brevity.
Try it like this (you have to make the variables you'll need available to the method)
$this->$methodName = function() use ($this, $methodName, $name){
echo "<br>".$methodName." is called";
return $this->$$name;
};
You should have access to the object context through $this.
Instead of updating the original question above, I include the complete solution here for anybody struggling with the same issues:
First of all, since the closure cannot have real object access, I needed to include the actual value with the "use" declaration when creating the closure function (see original __construct function above):
$value =& $this->$name;
$this->$methodName = function() use ($me, $methodName, &$value) {
return $value;
};
Secondly the __call magic method did not just need to call the closure function, it needed also to return any output from it. So instead of just calling $func(), I return $func();
This did the trick! :-)

Returning a reference to an object in PHP

I'm using PHP 5.2.14 and PearLog 1.12.3.
The latest documentation from the singleton method in Log.php (PEARLog) states:
You MUST call this method with the
$var = &Log::singleton()syntax.
Without the ampersand (&) in front of
the method name, you will not get a
reference; you will get a copy.
However, doing so generates the following warning:
STRICT NOTICE: Only variables should
be assigned by reference
The source for this function is:
public static function singleton($handler, $name = '', $ident = '',
$conf = array(), $level = PEAR_LOG_DEBUG)
{
static $instances;
if (!isset($instances)) $instances = array();
$signature = serialize(array($handler, $name, $ident, $conf, $level));
if (!isset($instances[$signature])) {
$instances[$signature] = Log::factory($handler, $name, $ident,
$conf, $level);
}
return $instances[$signature];
}
If I remove the & and use just:
$var = Log::singleton()
then I no longer get the warning. Also, if I do
$var = Log::singleton();
$var2 = Log::singleton();
then $var === var2 evaluates to true.
Question: Which is correct: the API documentation or the warning? (If the function returns an object, isn't it a reference anyway? Why would I need the ampersand ?
The way that objects are passed fundamentally changed in PHP5. In PHP4 they were always passed by value, meaning that a function or method that returned an object was actually passing a copy of the object back. This led to the use of the '&' operator, forcing the function to return an object by reference. In PHP5 objects are always passed by reference. To create a copy of an object you have to use the clone operator.
From having a very quick look at the source for the log package it appears that it maintains compatibility with PHP4. I don't think that you need the ampersand. PHP5 will return a reference to the object. Your test of '$var === $var2' has proved that the method returns an object and that the object is a reference to one object. If they were copies of an object the identity comparison would evaluate to false.
The warning is correct and the API documentation is outdated, objects are returned by reference since PHP5.
The way to deal with references changed a bit in PHP in PHP 5. Now they want the called function to decide to return by reference or by value, not the caller.
But usually PHP can sort this out by itself - like in your case it does detect that these two are the same object.
For more information about your E_STRICT check out the manual: http://www.php.net/manual/en/language.references.whatdo.php and how the pear function should be implemented: http://www.php.net/manual/en/language.references.return.php . (In my oppinion most parts of pear are outdated, the zend framework covers most of pear now.)
Edit: Large example of references:
error_reporting(E_STRICT);
ini_set('display_errors', 1);
class Settings
{
private static $_instance;
public static function getInstance()
{
if(self::$_instance == null)
{
self::$_instance = new Settings();
}
return self::$_instance;
}
public static function &getInstanceByRef()
{
if(self::$_instance == null)
{
self::$_instance = new Settings();
}
return self::$_instance;
}
private $counter = 0;
private function Settings()
{
}
public function getCounter()
{
return $this->counter;
}
public function setCounter($value)
{
$this->counter = $value;
}
}
$settings1 = Settings::getInstance();
$settings2 = Settings::getInstance();
echo $settings1->getCounter(); // 0
echo $settings2->getCounter(); // 0
$settings1->setCounter(42);
echo $settings1->getCounter(); // 42
echo $settings2->getCounter(); // 42
$settings3 = &Settings::getInstanceByRef(); // ref to private static $_instance !
$settings4 = &Settings::getInstanceByRef(); // ref to private static $_instance !
echo $settings3->getCounter(); // 42
echo $settings4->getCounter(); // 42
$settings3 = 5;
$settings5 = Settings::getInstance();
echo $settings5; // 5
As you can see even without refence getInstance is handled as reference. If you want to use references, both the caller and the called function must be marked as reference.
As a warning: return by reference can cause hard to find bugs: Returning by reference allows me to overwrite the private instance holding var. The expected behaviour in PHP would be that $settings3 is 5 but not the private static $_instance; This can result in very unpredictable code.

Categories