php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Doc Bug #69811 Cannot bind closure to scope of internal class stdClass
Submitted: 2015-06-12 12:55 UTC Modified: 2015-09-08 16:47 UTC
Votes:3
Avg. Score:3.7 ± 0.9
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:0 (0.0%)
From: olivier dot laviale at gmail dot com Assigned: cmb (profile)
Status: Closed Package: Class/Object related
PHP Version: 7.0.0alpha1 OS: Linux
Private report: No CVE-ID: None
 [2015-06-12 12:55 UTC] olivier dot laviale at gmail dot com
Description:
------------
Hi,

Looks like the following code is no longer possible with PHP7.

The following error is raised: "Cannot bind closure to scope of internal class stdClass".

I understand that PHP7 may introduce BC changes, but there's no mention about it in the documentation: http://php.net/manual/en/closure.bind.php

Test script:
---------------
<?php

class A
{
    private $a = 1;
    protected $b = 2;
    public $c = 3;

    static public function get_public_vars()
    {
        $get_public_vars = Closure::bind(function($object) {
            return get_object_vars($object);
        }, null, 'stdClass');

        return $get_public_vars($this);
    }
}

var_dump(A::get_public_vars(new A));

Expected result:
----------------
[ 'c' => 3 ]

Actual result:
--------------
Error: Cannot bind closure to scope of internal class stdClass

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-06-12 14:06 UTC] laruence@php.net
-Type: Bug +Type: Documentation Problem
 [2015-06-12 14:07 UTC] laruence@php.net
-Package: Scripting Engine problem +Package: Documentation problem
 [2015-06-13 06:25 UTC] kalle@php.net
To clarify Laurence's change; This is intended behaviour that you cannot bind a closure to an class defined internally.

Also I think you have a mistake in the example, as you pass a newly created instance of 'A' to the 'A::get_public_vars()' method, but 'A::get_public_vars()' still assumes '$this' in the return statement, not that it would render the practice of binding closures  to internally classes anymore allowed ;-)
 [2015-06-13 06:25 UTC] kalle@php.net
-Status: Open +Status: Analyzed
 [2015-06-14 21:39 UTC] olivier dot laviale at gmail dot com
Thanks for your reply Kalle. There's indeed an error in my code example, should be as follows:

```
<?php

class A
{
    private $a = 1;
    protected $b = 2;
    public $c = 3;

    static public function get_public_vars($object)
    {
        $get_public_vars = Closure::bind(function($object) {
            return get_object_vars($object);
        }, null, 'stdClass');

        return $get_public_vars($object);
    }
}

var_dump(A::get_public_vars(new A));
```

Now that we can't bind `stdClass`, what's the best way to get *only* the public properties of an object, since get_object_vars() executes from the current scope?
 [2015-06-16 22:24 UTC] kalle@php.net
Hi Olivier

For the time being, I can only think of the following posibilities to achieve what you are trying to:

1) Simply create your own stdClass object, or use Anonymous Classes (also available in PHP7)


2) Reflection. This is heavy and really should not be used in production code:
<?php
	class Alphabet
	{
		public $a, $b, $c;
		protected $d, $e, $f;
		private $g, $h, $i;

		public function __construct()
		{
			foreach(range('a', 'i') as $letter)
			{
				$this->{$letter} = random_int(0, 10000);
			}
		}

		public function getPublicVars(Alphabet $alphabet)
		{
			$ref 	= new ReflectionObject($alphabet);
			$props	= [];

			foreach($ref->getProperties(ReflectionProperty::IS_PUBLIC) as $prop)
			{
				$props[$prop->name] = $prop->getValue($alphabet);
			}

			return($props);
		}
	}

	var_dump(Alphabet::getPublicVars(new Alphabet));
?>

3) Casting to an array:
<?php
	class Alphabet
	{
		public $a, $b, $c;
		protected $d, $e, $f;
		private $g, $h, $i;

		public function __construct()
		{
			foreach(range('a', 'i') as $letter)
			{
				$this->{$letter} = random_int(0, 10000);
			}
		}

		public function getPublicVars(Alphabet $alphabet)
		{
			return(array_filter((array) $alphabet, function($key)
			{
				return($key{0} !== "\0");
			}, ARRAY_FILTER_USE_KEY));
		}
	}

	var_dump(Alphabet::getPublicVars(new Alphabet));
?>

This should be considered your last resort (and please do not tell anyone that the code was "promoted" from PHP.net as this is dirty stuff!)

I hope this can guide you a little further in the right direction at least :)
 [2015-09-08 16:45 UTC] cmb@php.net
Automatic comment from SVN on behalf of cmb
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=337785
Log: Closure::bind() doesn't allow to bind to scope of internal classes anymore (fixes #69811)
 [2015-09-08 16:47 UTC] cmb@php.net
-Status: Analyzed +Status: Closed -Package: Documentation problem +Package: Class/Object related -Assigned To: +Assigned To: cmb
 [2015-09-08 16:47 UTC] cmb@php.net
This bug has been fixed in the documentation's XML sources. Since the
online and downloadable versions of the documentation need some time
to get updated, we would like to ask you to be a bit patient.

Thank you for the report, and for helping us make our documentation better.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 18 21:01:29 2024 UTC