在PHP中,您可以实例化对象并在同一行上调用方法吗?


126

我想做的是这样的:

$method_result = new Obj()->method();

不必这样做:

$obj = new Obj();
$method_result = $obj->method();

在我的特定情况下,结果对我而言实际上并不重要。但是,有办法吗?


4
顺便说一句,如果您没有使用5.4(您可能没有使用),则可以定义一个辅助函数,该函数仅将一个对象返回到链式对象中。}(从laravel:P中挑选出窍门)..然后,您可以使用(new Obj)-> method()
kapv89 2012年

顺便说一句,如果您发现自己经常这样做,那么值得考虑是否my_method应该声明它static
制造商史蒂夫

Answers:


166

您要求的功能可从PHP 5.4获得。以下是PHP 5.4中的新功能列表:

http://php.net/manual/zh/migration54.new-features.php

以及新功能列表中的相关部分:

添加了对实例化的类成员访问,例如(new Foo)-> bar()。


9
请注意,这也意味着您可以(new Foo)->property根据需要进行操作。
dave1010 2012年

1
请注意,您还不能以这种方式分配属性。(新Foo)-> property ='property';
CMCDragonkai 2014年

7
@CMCDragonkai从逻辑上讲是有道理的;该对象仅在语句期间存在(new Foo)->property-您存储的值无处可去,因为在此之后该对象将不再存在,因为它没有存储在任何地方。
thomasrutter

1
@CMCDragonkai您可以通过调用相应的setter来以这种方式分配属性,所有您需要做的就是添加return $this到setter中。这也将允许您链接二传手。
iloo

我有个问题。除了能够重用对象之外,在另一行上声明对象并将其保存为变量是否有任何好处?
泰勒·施瓦岑堡

37

你不能做你要求的; 但是您可以使用以下事实来“欺骗”:在PHP中,您可以拥有一个与类同名的函数;这些名字不会冲突。

因此,如果您声明了这样的类:

class Test {
    public function __construct($param) {
        $this->_var = $param;
    }
    public function myMethod() {
        return $this->_var * 2;
    }
    protected $_var;
}

然后,您可以声明一个函数,该函数返回该类的实例-并且具有与该类完全相同的名称:

function Test($param) {
    return new Test($param);
}

现在,可以像您所要求的那样使用单线-唯一的事情是您正在调用该函数,因此不使用new:

$a = Test(10)->myMethod();
var_dump($a);

它的工作原理:在这里,我得到:

int 20

作为输出。


而且,更好的是,您可以在函数中放一些phpdoc:

/**
 * @return Test
 */
function Test($param) {
    return new Test($param);
}

这样,您甚至可以在IDE中获得提示-至少在Eclipse PDT 2.x中;看到screeshot:



编辑2010-11-30:仅作参考,几天前已经提交了新的RFC,建议将该功能添加到将来的PHP版本中。

请参阅:请求注释:实例和方法调用/属性访问

因此,也许可以在PHP 5.4或其他将来的版本中进行类似的操作:

(new foo())->bar()
(new $foo())->bar
(new $bar->y)->x
(new foo)[0]

19

您可以通过定义一个身份函数来更通用地做到这一点:

function identity($x) {
    return $x;
}

identity(new Obj)->method();

这样,您无需为每个类定义一个函数。


10
不错的解决方案,因为它强调了此限制的愚蠢性:)
Ole 2012年

19

怎么样:

$obj = new Obj(); $method_result = $obj->method(); // ?

:P


16

不,这是不可能的。
您需要先将实例分配给变量,然后才能调用其任何方法。

如果您真的不想这样做,可以按照罗普斯塔建议的那样使用工厂:

class ObjFactory{
  public static function newObj(){
      return new Obj();
  }
}
ObjFactory::newObj()->method();

4
皮姆的答案是正确的。另外,如果您不想创建对象的实例,则可以使用静态函数
Mark

使用此方法,我们被迫public static function代替使用public function。建议使用静态?
ichimaru

6

您可以使用静态工厂方法来生成对象:

ObjectFactory::NewObj()->method();

3
无需单独的工厂;同一类中的静态方法将完成相同的操作。
Brilliand 2014年

3

我也一直在寻找一种形式来实现这一点,作为将日期从一种格式转换为另一种格式的单个表达式的一部分。我喜欢在一行代码中执行此操作,因为它是单个逻辑操作。因此,这有点晦涩难懂,但是它使您可以在一行中实例化和使用日期对象:

$newDateString = ($d = new DateTime('2011-08-30') ? $d->format('F d, Y') : '');

单行将日期字符串从一种格式转换为另一种格式的另一种方法是使用助手功能来管理代码的OO部分:

function convertDate($oldDateString,$newDateFormatString) {
    $d = new DateTime($oldDateString);
    return $d->format($newDateFormatString);
}

$myNewDate = convertDate($myOldDate,'F d, Y');

我认为面向对象的方法很酷,而且很有必要,但有时可能很乏味,需要太多的步骤才能完成简单的操作。


0

我认为这是很老的问题了,但是我认为这里应该提到:

称为“ __call()”的特殊类方法可用于在类内部创建新项目。您可以这样使用它:

<?php
class test
{

function __call($func,$args)
{
    echo "I am here - $func\n";
}

}

    $a = new test();
    $a->new( "My new class" );
?>

输出应为:

I am here - new

因此,您可以欺骗PHP在顶级类(或实际上是任何类)中创建“新”命令,然后将include命令放入__call()函数中,以包含所需的类。当然,您可能希望测试$ func以确保它是发送给__call()命令的“新”命令,并且(当然)由于__call()的工作方式,您可能还具有其他命令。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.