2015-11-02 14:17:32 11065次浏览 3条回答 4 悬赏 50 金钱

Yii2创建form表单是个常见的情景,今天偶然的机会看到from表单id的两种写法:
第一种写法:

<?php $form = ActiveForm::begin([
    'id'=>'myForm', //设置form表单id
    'method'=>'get',
    'options' => ['class'=>'form-horizontal']
]);?>

第二种写法:

<?php $form = ActiveForm::begin([
    'method'=>'get',
    'options' => ['class'=>'form-horizontal''id'=>'myForm'] //id放在属性里
]);?>

两种写法经过的源码有一点点区别,简单的来看下源码:
首先,是ActiveForm::begin()这个方法,他是在yiisoft\yii2\base\Widget.php里的begin()方法

public static function begin($config = [])
{
    $config['class'] = get_called_class();
    /* @var $widget Widget */
    $widget = Yii::createObject($config);
    static::$stack[] = $widget;
    return $widget;
}

这个方法返回的是ActiveForm(yiisoft\yii2\widgets\ActiveForm)对象,而不是Widget对象,我们打印下返回的$widget对象,看看两种情况这个对象哪里不一样var_dump($widget);

第一种id的表单写法结果是:

object(yii\widgets\ActiveForm)#56 (29) { ["action"]=> string(0) "" ["method"]=> string(3) "get" ["options"]=> array(2) { ["class"]=> string(15) "form-horizontal" ["id"]=> string(6) "myForm" } ["fieldClass"]=> string(23) "yii\widgets\ActiveField" ["fieldConfig"]=> array(0) { } ["encodeErrorSummary"]=> bool(true) ["errorSummaryCssClass"]=> string(13) "error-summary" ["requiredCssClass"]=> string(8) "required" ["errorCssClass"]=> string(9) "has-error" ["successCssClass"]=> string(11) "has-success" ["validatingCssClass"]=> string(10) "validating" ["enableClientValidation"]=> bool(true) ["enableAjaxValidation"]=> bool(false) ["enableClientScript"]=> bool(true) ["validationUrl"]=> NULL ["validateOnSubmit"]=> bool(true) ["validateOnChange"]=> bool(true) ["validateOnBlur"]=> bool(true) ["validateOnType"]=> bool(false) ["validationDelay"]=> int(500) ["ajaxParam"]=> string(4) "ajax" ["ajaxDataType"]=> string(4) "json" ["scrollToError"]=> bool(true) ["attributes"]=> array(0) { } ["_fields":"yii\widgets\ActiveForm":private]=> array(0) { } ["_id":"yii\base\Widget":private]=> string(6) "myForm" ["_view":"yii\base\Widget":private]=> NULL ["_events":"yii\base\Component":private]=> array(0) { } ["_behaviors":"yii\base\Component":private]=> NULL }

第二种id表单结果:

object(yii\widgets\ActiveForm)#56 (29) { ["action"]=> string(0) "" ["method"]=> string(3) "get" ["options"]=> array(2) { ["class"]=> string(15) "form-horizontal" ["id"]=> string(6) "myForm" } ["fieldClass"]=> string(23) "yii\widgets\ActiveField" ["fieldConfig"]=> array(0) { } ["encodeErrorSummary"]=> bool(true) ["errorSummaryCssClass"]=> string(13) "error-summary" ["requiredCssClass"]=> string(8) "required" ["errorCssClass"]=> string(9) "has-error" ["successCssClass"]=> string(11) "has-success" ["validatingCssClass"]=> string(10) "validating" ["enableClientValidation"]=> bool(true) ["enableAjaxValidation"]=> bool(false) ["enableClientScript"]=> bool(true) ["validationUrl"]=> NULL ["validateOnSubmit"]=> bool(true) ["validateOnChange"]=> bool(true) ["validateOnBlur"]=> bool(true) ["validateOnType"]=> bool(false) ["validationDelay"]=> int(500) ["ajaxParam"]=> string(4) "ajax" ["ajaxDataType"]=> string(4) "json" ["scrollToError"]=> bool(true) ["attributes"]=> array(0) { } ["_fields":"yii\widgets\ActiveForm":private]=> array(0) { } ["_id":"yii\base\Widget":private]=> NULL ["_view":"yii\base\Widget":private]=> NULL ["_events":"yii\base\Component":private]=> array(0) { } ["_behaviors":"yii\base\Component":private]=> NULL }

可以看出,结果差不多一样,关键看后面几行["_id":"yii\base\Widget":private]这个对应的值不一样,第一种的值是自己定义的id(myForm),第二种值为空,这里的_id是Widget.php里的一个属性(定义在110行左右)

begin()运行后,是运行init()方法(在yiisoft\yii2\widgets\ActiveForm):

public function init()
{
    if (!isset($this->options['id'])) {
        $this->options['id'] = $this->getId();
    }
    echo Html::beginForm($this->action, $this->method, $this->options);
}

这里的if语句不解,$this->options['id'])不是两种情况都有值的吗(var_dump($widget);),为什么第2种没运行进来第1种却运行进来了???

问题解决了,之前理解错了一直以为运行完begin后才会运行init的,原来是运行begin的时候会调用init的

最佳答案

  • 性感的农民 发布于 2015-11-02 15:41 举报

    如果你在options中没有指定id,那么框架就使用w0,w1,w2...这样的id.

    1 条回复
    回复于 2015-11-02 15:41 回复

    之前理解错了一直以为运行完begin后才会运行init的,原来是运行begin的时候会调用init的

  • 回答于 2015-11-02 16:27 举报

    首先你要理解init();在什么时候调用。
    是在object创建的时候调用的魔术方法__construct();里面调用到init();

    而静态方法的调用不会触发construct();
    所以ActiveForm::begin();先执行begin();方法,在begin();方法中调用$widget = Yii::createObject($config);的时候,才触发
    construct();调用到init();
    而$this->options中options的值是在__construct();中Yii::configure($this, $config);方法设置,所以你会发现你方法1中有init();有值而2中没值。

    7 条回复
    回复于 2015-11-03 08:31 回复

    好帖子 顶

    回复于 2015-11-03 08:34 回复

    $widget = Yii::createObject($config)这个源码好难理解

    回复于 2015-11-03 09:41 回复

    这个就真的很复杂了。包含依赖注入(DI)和依赖注入容器,在权威教程http://www.yiichina.com/doc/guide/2.0/concept-di-container 你可以看下。。这个我也一知半解,解释不清楚。

    回复于 2015-11-06 21:26 回复

    在Widget::begin()方法里调用$widget = Yii::createObject($config);的时候,才触发construct();调用到init();这里init方法是widget子类ActiveForm的方法 父类可以调用子类的方法吗

    回复于 2015-11-07 14:02 回复

    这里ActiveForm的init是覆盖了父类的init方法。

    回复于 2015-11-07 19:35 回复

    ActiveForm父类Widget没看到有init方法呀

    回复于 2015-11-09 09:47 回复

    object类有,几乎所有的类的继承至object类。

    , 觉得很赞
  • 回答于 2015-11-02 18:22 举报

    农民和楼上的解释挺好的

您需要登录后才可以回答。登录 | 立即注册
xyf90314
副总裁

xyf90314

注册时间:2015-03-04
最后登录:2023-03-13
在线时长:95小时23分
  • 粉丝21
  • 金钱5257
  • 威望40
  • 积分6607

热门问题