Warning: preg_replace_callback() [function.preg-replace-callback]: Requires argument 2, 'info', to be a valid callback in [...]
public function getDisplay(){
$info = array_merge($this->info,array());
return preg_replace_callback('!\{\{(\w+)\}\}!', 'info', $this->display);
}
In a public function from "MyClass", stopped working when I moved from another class to this one. Which was:
public function getEdit( $type){
$all_info = $this->info;
return preg_replace_callback('!\{\{(\w+)\}\}!', 'all_info', $edit_contents);
}
Both are cleaned up, and now I can't retest with previous class because it's already long gone.
I'm sure using variables is not allowed, but it was working, so I'm clueless.
When I do this, as suggested in some stackoverflow thread, but obviously it's not made to be used within objects:
public function getDisplay(){
$display_info = $this->info;
function display_info($matches) {
global $display_info;
return $display_info[$matches[1]];
}
return preg_replace_callback('!\{\{(\w+)\}\}!', 'display_info', $this->display);
}
So I need some love and guidance cuz php is driving me crazy this week...
Instead of using anonymous functions or more complex methods, you can just use one of methods supported for passing callbacks (see the documentation on callbacks):
A method of an instantiated object is passed as an array containing an object at index 0 and the method name at index 1.
To pass "info" method of current object as a callback, just do the following:
array($this, 'info')
and pass it wherever you want to use "info" method as a callback within one of the objects other methods.
The correct way to do this would be with a closure:
public function getDisplay() {
// While $this support in closures has been recently added (>=5.4.0), it's
// not yet widely available, so we'll get another reference to the current
// instance into $that first:
$that = $this;
// Now we'll write that preg... line of which you speak, with a closure:
return preg_replace_callback('!\{\{(\w+)\}\}!', function($matches) use($that) {
return $that->info[$matches[1]];
}, $this->display);
}
This solved it:
public function getDisplay(){
return preg_replace_callback('!\{\{(\w+)\}\}!', array(get_class($this), '_preg_replace_callback'), $this->display);
}
private function _preg_replace_callback($matches){
return $this->info[$matches[1]];
}
I did try this approach before, but didn't use the get_class() function to wrap $this. Oh bother...
Related
I'm trying to run a method on each element inside a collection. It's an object method residing in the same class:
protected function doSomething()
{
$discoveries = $this->findSomething();
$discoveries->each([$this, 'doSomethingElse']);
}
protected function doSomethingElse($element)
{
$element->bar();
// And some more
}
If I precede the call on Collection::each with the check is_callable([$this, 'doSomethingElse']) it returns true, so apparently it is callable. The call itself however throws an exception:
Type error: Argument 1 passed to Illuminate\Support\Collection::each() must
be callable, array given, called in ---.php on line 46
The method trying to be called can be found here.
I'm bypassing this by just passing a closure that itself simply calls that function, but this would definitely a much cleaner solution and I can't find out why it throws the error.
Change the visibility of your callback method to public.
protected function doSomething()
{
$discoveries = $this->findSomething();
$discoveries->each([$this, 'doSomethingElse']);
}
public function doSomethingElse($element)
{
$element->bar();
// And some more
}
Since PHP 7.1 you can leave your function protected. Now you can write:
protected function doSomething()
{
$discoveries = $this->findSomething();
$discoveries->each(\Closure::fromCallable([$this, 'doSomethingElse']));
}
protected function doSomethingElse($element)
{
$element->bar();
// And some more
}
Source
function with callback
public function foo(callable $callback){
$callback('something')
}
named function for callback
public function do($something) {
//
}
result
foo(function ($something) {
//
})
or call named function
foo(\Closure::fromCallable([$this, 'do']))
or
foo(this->do(...))
PHP >= 5.4
I wasn't able to reproduce your error, but my guess is that you should use $discoveries instead of $this in the callback array, like so:
$discoveries->each([$discoveries, 'doSomethingElse']);
Even though $discoveries and $this are of the same class, and therefore can access each other's protected and private methods, the type-hinting functionality may not check that the object in the callback array is the same class as the current class. However, the is_callable() method will check for this, which may explain why it returns true when you call it from inside the each() method.
PHP < 5.4
There is no type named callable, so when you use it as a type hint, it is referring to a class named callable. See this answer.
This seems straightforward, but the below code is giving the following error. Any suggestions?
usort() expects parameter 2 to be a valid callback, function 'cmp' not
found or invalid function name
My code:
function cmp($item1, $item2) {
return strcmp(strtolower($item1->last_name), strtolower($item2->last_name));
}
public function get_people() {
usort($this->my_array, 'cmp');
}
Since you use $this->my_array and the function has the keyword public, I'm going to assume these two methods are in a class definition, so you also have to define, that you want to call a class method and not a normal function.
This means you have to change:
usort($this->my_array, 'cmp');
to:
usort($this->my_array, [$this, 'cmp']);
//^^^^^ So it will call the class method and not a normal global function
It seems you have this within a class so there's two ways you can do this.
first way, by telling it the method exists on the current class
public function get_people() {
usort($this->my_array, array($this, 'cmp'));
}
second way, using closures
public function get_people() {
usort($this->my_array, function($item1, $item2) {
return strcmp(strtolower($item1->last_name), strtolower($item2->last_name));
});
}
I personally prefer the closure way as this function is only used by this sort function.
Yes, you're inside a class. There are many ways how to use class or object functions for callback, see PHP manual. Example:
public function get_people() {
usort($this->my_array, array($this, 'cmp'));
}
I created a basic class to play with Closure object a bit. I don't understand the behaviour of this application/closures so I wanted to ask a few things. My mind is pretty cloudy at the moment so I don't know why something runs or why not.
<?php
class Route
{
public static $bindings = array();
public static $dispatch = array();
public static function bind($bind)
{
self::$bindings[] = $bind;
}
public static function getAllBindings()
{
return (array) self::$bindings;
}
public static function get($binding, Closure $dispatch)
{
if(in_array($binding, self::$bindings))
{
if(is_callable($dispatch))
{
return call_user_func($dispatch);
}
else
{
die("Dispatch method is not callable.");
}
}
else
{
die("Binding is not found in bindings array.");
}
}
public static function test()
{
echo "Test ran!";
}
}
Basically, we bind bindings (such as /admin, /account, /profile etc.) Then, we try to call a method using closure.
// Let's bind account and admin as available bindings
Route::bind('account');
Route::bind('admin');
// Let's try doing a get call with parameter "account"
Route::get('account', function() {
// This is where I'm stuck. See below examples:
// Route::test();
// return "test";
// return "testa";
// return self::test();
});
If you checked above, here are my questions:
If I provide a non-existent method, is_callable check does not run and I get a php fatal error. Isn't is_callable a valid check for checking inexistent methods? Why does it happen?
If I provide return "Test"; in the closure, is my $closure parameter in get method going to contain "Test" string?
Can I pass a methods from different classes inside the closure? Like:
Route::get('account', function () {
if(User::isLoggedIn() !== true)
return Error::login_error('Unauthorized.');
});
If so, in which scope this call is being made? PHP's scope in closure, or does call_user_func call it inside Route class' scope since it is passed to it via closure? (To clear it a bit more, PHP's scope may do $route->get but Closure scope may use $this->get)
Is there any way to dump Closure object like var_dump/print_r to see it's contents?
A short guidance will get me going. I know PHP but using closures is pretty new to me.
Thanks alot and I appreciate your replies.
You won't need that is_callable() check as the Closure type hint in the method declaration already ensures this. Also you don't need call_user_func(). This will give you the following get() method:
public static function get($binding, Closure $dispatch)
{
if(!in_array($binding, self::$bindings))
{
die("Binding is not found in bindings array.");
}
return $dispatch();
}
Note : Currently the $binding param will just being used in a check, but not as a param to $dispatch(), what would I have expected. I can't see a reason for that. You should rethink this part
I found another hidden question in your post:
// Let's try doing a get call with parameter "account"
Route::get('account', function() {
// This is where I'm stuck. See below examples:
// Route::test();
// return "test";
// return "testa";
// return self::test();
});
It should look like:
// Let's try doing a get call with parameter "account"
Route::get('account', function() {
// Both should work well:
// Route::test();
// .. or
// return self::test();
});
I'm a little confused about the situation shown in this code...
class DirEnt
{
public function PopulateDirectory($path)
{
/*... code ...*/
while ($file = readdir($folder))
{
is_dir($file) ? $dtype = DType::Folder : $dtype = Dtype::File;
$this->push_back(new SomeClass($file, $dtype));
}
/*... code ...*/
}
//Element inserter.
public function push_back($element)
{
//Insert the element.
}
}
Why do I need to use either $this->push_back(new SomeClass($file, $dtype)) or self::push_back(new SomeClass($file, $dtype)) to call the member function push_back? I can't seem to access it just by doing push_back(new SomeClass($file, $dtype)) like I would have expected. I read When to use self over $this? but it didn't answer why I need one of them at all (or if I do at all, maybe I messed something else up).
Why is this specification required when the members are both non-static and in the same class? Shouldn't all member functions be visible and known from other member functions in the same class?
PS: It works fine with $this-> and self:: but says the functions unknown when neither is present on the push_back call.
$this->push_back will call the method as part of the CURRENT object.
self::push_back calls the method as a static, which means you can't use $this within push_back.
push_back() by itself will attempt to call a push-back function from the global scope, not the push_back in your object. It is not an "object call", it's just a plain-jane function call, just as calling printf or is_readable() within an object calls the usual core PHP functions.
I cant seem to access it just by doing push_back(new SomeClass($file, $dtype)) like I would have expected.
This way you call push_back() as a function. There is no way around $this (for object methods) or self::/static:: (for class methods), because it would result into ambiguity
Just remember: PHP is not Java ;)
You can access like this
public static function abc($process_id){
return 1;
}
public static function xyz(){
$myflag=self::abc();
return $myflag;
}
output : 1
I have an object that uses the magic __call method to call methods on different objects.
There are times when this method will be used to call a method that requires one or more of its parameters to be a reference.
As of php 5.3 call-time pass-by-reference has been deprecated so I cant rely on passing the arguments by reference. I need to predict if the arguments need to be passed by reference or value!
I will try to explain this in code. I have the following two classes:
Main_Object
Extension_Object
note: there is no inheritance structure between the two classes.
class Main_Object {
public function __call($method, $arguments)
{
// check this method is in an extended class
// …
$ext = new Extension_Object();
// call method in extension object
return call_user_func_array(array($ext, $method), $arguments);
}
}
class Extension_Object {
// takes two arguments
public function foo($p1, $p2)
{
// ...
}
// takes two arguments, the first being a reference
public function bar(&$p1, $p2)
{
// ...
}
}
Currently I cant find a way to call bar() without generating a PHP error or warning
$obj = new Main_Object();
// works as expected
$obj->foo($bacon, $cheese);
// MESSAGE call-time pass-by-reference has been deprecated
$obj->bar(&$bacon, $cheese);
// WARNING parameter 1 expected to be a reference
$obj->bar($bacon, $cheese);
You could set allow_call_time_pass_reference = 1; but it's far from a good solution. There doesn't seem to be another way. Reflection might yield an answer, but I personally don't know enough about this particular issue to really advise on that...
Is it possible to pass parameters by reference using call_user_func_array()?
PHP: call_user_func_array: pass by reference issue
You could manually convert the arguments like so.
public function __call($method, $arguments) {
$referenceable_arguments = array();
// Gets around a limitation in PHP.
foreach ($arguments as &$argument) {
$referenceable_arguments[] = &$argument;
}
return call_user_func_array(array($this->delegate, $method), $referenceable_arguments);
}