Skip to content

Commit 8b68274

Browse files
committed
Fix method calls for PHP objects wrapped in variant
As is, methods of PHP can never be called, because we're first trying to read the property with the name of the method. We fix this by first checking for `DISPATCH_METHOD` and treat that as method call, if the method would be callable. Only otherwise we try to access the respective property. It needs to be noted that this breaks code which accesses a property of an object, which defines a method of the same name. However, instances of such classes should never be wrapped in variants, because this can't be distinguished by COM anyway. Closes GH-16945.
1 parent fdd3839 commit 8b68274

File tree

3 files changed

+51
-7
lines changed

3 files changed

+51
-7
lines changed

NEWS

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ PHP NEWS
33
?? ??? ????, PHP 8.5.0alpha1
44

55
- COM:
6-
. Fix property access of PHP objects wrapped in variant. (cmb)
6+
. Fixed property access of PHP objects wrapped in variant. (cmb)
7+
. Fixed method calls for PHP objects wrapped in variant. (cmb)
78

89
- Core:
910
. Fixed bug GH-16665 (\array and \callable should not be usable in

ext/com_dotnet/com_wrapper.c

+8-6
Original file line numberDiff line numberDiff line change
@@ -257,13 +257,10 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex(
257257
/* TODO: if PHP raises an exception here, we should catch it
258258
* and expose it as a COM exception */
259259

260-
if (wFlags & DISPATCH_PROPERTYGET) {
261-
retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), 1, &rv);
262-
ret = S_OK;
263-
} else if (wFlags & DISPATCH_PROPERTYPUT) {
260+
if (wFlags & DISPATCH_PROPERTYPUT) {
264261
zend_update_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), &params[0]);
265262
ret = S_OK;
266-
} else if (wFlags & DISPATCH_METHOD) {
263+
} else if (wFlags & DISPATCH_METHOD && zend_is_callable_ex(name, Z_OBJ(disp->object), 0, NULL, NULL, NULL)) {
267264
zend_try {
268265
retval = &rv;
269266
if (SUCCESS == call_user_function(NULL, &disp->object, name,
@@ -289,6 +286,9 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex(
289286
trace("something blew up\n");
290287
ret = DISP_E_EXCEPTION;
291288
} zend_end_try();
289+
} else if (wFlags & DISPATCH_PROPERTYGET) {
290+
retval = zend_read_property(Z_OBJCE(disp->object), Z_OBJ(disp->object), Z_STRVAL_P(name), Z_STRLEN_P(name), 1, &rv);
291+
ret = S_OK;
292292
} else {
293293
trace("Don't know how to handle this invocation %08x\n", wFlags);
294294
}
@@ -307,7 +307,9 @@ static HRESULT STDMETHODCALLTYPE disp_invokeex(
307307
VariantInit(pvarRes);
308308
php_com_variant_from_zval(pvarRes, retval, COMG(code_page));
309309
}
310-
// zval_ptr_dtor(retval); // TODO needed for function calls?
310+
if (retval == &rv) {
311+
zval_ptr_dtor(retval);
312+
}
311313
} else if (pvarRes) {
312314
VariantInit(pvarRes);
313315
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
Testing reading properties and calling functions
3+
--EXTENSIONS--
4+
com_dotnet
5+
--FILE--
6+
<?php
7+
class MyClass {
8+
public $foo = "property";
9+
public $bar = "bar";
10+
public function foo() {
11+
return "method";
12+
}
13+
public function stdClass() {
14+
return new stdclass();
15+
}
16+
}
17+
18+
$o = new MyClass();
19+
$v = new variant($o);
20+
var_dump($v->foo);
21+
var_dump($v->foo());
22+
var_dump($v->bar);
23+
var_dump($v->bar());
24+
var_dump($v->stdclass);
25+
var_dump($v->stdclass());
26+
try {
27+
var_dump($v->qux);
28+
} catch (com_exception $ex) {
29+
echo $ex->getMessage(), "\n";
30+
}
31+
?>
32+
--EXPECTF--
33+
string(6) "method"
34+
string(6) "method"
35+
string(3) "bar"
36+
string(3) "bar"
37+
object(variant)#%d (0) {
38+
}
39+
object(variant)#%d (0) {
40+
}
41+
Unable to lookup `qux': %s

0 commit comments

Comments
 (0)