怎样设置数组类型的成员变量的值?

#1 stalker

class test extends spController
{
    public function __construct()
   {
          $this->var = array('a'=>1, 'b'=>2);
   }

   public function index()
   {
          $this->var['a'] = 3;
   }
}
这样不提示出错   但是在视图中却接收不到设置的新值  正确的设置方法应该是?

2013-04-04 00:31:05

#2 jake

由于$this是通过魔术方法实现的,所以不能直接用。
class test extends spController
{
        var $tmp;
    public function __construct()
   {
          $this->tmp = array('a'=>1, 'b'=>2);
   }

   public function index()
   {
          $this->tmp['a'] = 3;
          $this->var = $this->tmp;
   }
}

2013-04-04 08:16:00

#3 stalker

class top extends spController
public function __set($name,$value)
{}
public function display($tplname, $output = TRUE)
{
//水哥新增加代码部分
//获得所有public成员变量,赋值给模板
$array=get_object_vars($this);
foreach($array as $name => $value){
if(TRUE == $GLOBALS['G_SP']['view']['enabled'] && false !== $value){
$this->v->engine->assign(array($name=>$value));
}
$this->__template_vals[$name] = $value;
}
//ends of 水哥

@ob_start();
if(TRUE == $GLOBALS['G_SP']['view']['enabled']){
$this->v->display($tplname);
}else{
extract($this->__template_vals);
require($tplname);
}
if( TRUE != $output )return ob_get_clean();
}
}
我搜了下之前的帖子  感觉这位水哥的代码不错    既实现了在视图最终输出的时候才给视图赋值最后的成员变量值     也实现了通过给成员变量赋值的方式给视图类赋值 因为对于同一个成员变量相同的controller下不同的action可能需要不同的值(但大部分都是一样的)  所以希望认真考虑一下这种情况  相信以后遇到这个问题的人会越来越多

2013-04-04 11:12:36

#4 stalker

魔术函数貌似不能再重载了  所以还只能修改spController  

2013-04-04 11:30:59

#5 jake

1. get_object_vars获取不到魔术方法设置的变量,所以上面的代码基本没什么用处。
2. 正常的类变量,是否应该可以在模板里面读取,这个要衡量(并不是没有认真对待): 我的意见是普通的类成员变量,那是PHP语法;而通过魔术方法设置的$this是给模板赋值的变量,是一种特殊约定的惯例语法,分开对待是很有好处的,V层最大的问题是很多开发者都想把它当作C或M层用。
3. “相信以后遇到这个问题的人会越来越多”,这个不好意思,是会越来越少。因为先处理最后再赋值给模板,这是一个良好的编程习惯,相信初学者在逐渐学习中就会慢慢掌握这种技巧。

PS:加个编程习惯的建议:控制器最好不要在action里面调用action。

2013-04-04 11:52:19

#6 stalker

经测试  上面的代码不变  只要把spController里的魔术函数注释掉就可以实现   可能魔术函数不允许被重载  因为调用get_object_vars的时候变量还没有赋值给视图类所以是没有问题的

举个最简单的例子  我建了一个继承自spController的所有控制器的基类 top 它有个成员变量title  大部分页面都通过在action中调用$this->title来表示视图中的标题
class top extends spController
{
     public function __construct()
     {
          parent::__construct();
          $this->title = 'ZZZZZZ';
     }
}


      <{$title}>

....
而某些页面的标题需要不太一样  按照现在的情况就需要以下两个步骤才能实现:

第一:在控制器里设置一个不同于title的成员变量
class test extends top
{
    public function index()
    {
         $this->abctitle = 'XXXXX - '.$this->title;
    }
}
第二:在视图模板中修改smarty变量


      <{$abctitle}>

....
而如果在生成视图的时候再给视图类赋值的话这两步都不需要  

2013-04-04 16:40:18

#7 stalker

不知道是没明白你的意思   还是你没明白我的意思   我认为控制器的成员变量也应该有成员变量的作用   而不是一调用就直接通过魔术函数赋值给视图   因为不管控制器的成员变量还是视图的成员变量  保证在display之前就确定它的值  甚至在构造函数的时候就确定它的值是不现实的   我也不明白这违反什么MVC编程规范了

2013-04-04 16:47:06

#8 jake

stalker 发表于 2013-4-4 16:47
不知道是没明白你的意思   还是你没明白我的意思   我认为控制器的成员变量也应该有成员变量的作用   而不 ...
上面的abctitle实在是钻牛角尖了。为什么不能是:

{if $abctitle}{$abctitle}{else}{$title}{/if}

或者更简单一点

{$abctitle|default:$title}



呵呵,或者要你尝试明白我的意思了,你觉得是“控制器的成员变量也应该有成员变量的作用   而不是一调用就直接通过魔术函数赋值给视图”,其实一直都是对的,你可以试试真正的成员变量,它的确是可以有你说的功能。记得真正的成员变量是必须先定义,再赋值,不会通过魔术方法来进行。我上面例子中的$tmp就是真正的成员变量,可以当普通变量使用。

而你在全部的代码里面,只盯着魔术方法的假成员变量(没有成员变量定义的),觉得这种假的成员变量也应该是可以像真的成员变量一样使用。只能说行不通,因为像get_object_vars这种函数是无法取得魔术方法生成的假成员变量。

我的意思是,真正的成员变量(有定义的)是PHP语法,可以按照普通类的成员变量一样使用。而假的成员变量(没有定义,通过魔术方法实现的),就是一种约定的模板赋值方法。如果你能区分这两种变量,那么就能懂是什么意思了。(比如说你知道上面我的代码中$var是哪种吗?)

说违反MVC规则那倒不至于,只是编程习惯,到最后一刻才给模板赋值,这是比较好的。也就是一开始用真实成员变量保存值,到了最后才用假的成员变量赋值给模板,这种做法。




2013-04-04 17:16:50

#9 stalker

原来事先声明的成员变量才是控制器的成员变量   不事先声明的就直接赋值给视图了  但是跟上面我举的例子类似  本来一个title就可以了  现在多出来个abctitle  还要进行if逻辑判断  现在我事先声明了控制器的成员变量了  但是最后给视图赋值的时候又调用不了了  因为它触发不了魔术函数__set了  又要声明一个在控制器里不存在的新变量名  而不是控制器和视图可以用一样的变量名?这个也不会造成冲突  实现也不难  所要做的只不过是把魔术函数的内容移动在display里而已


2013-04-04 17:41:35

#10 jake

stalker 发表于 2013-4-4 17:41
原来事先声明的成员变量才是控制器的成员变量   不事先声明的就直接赋值给视图了  但是跟上面我举的例子类 ...
“原来事先声明的成员变量才是控制器的成员变量   不事先声明的就直接赋值给视图了”,懂了这点就行,没必要纠结。

实际上平时开发控制器只有构造函数要传值给action,所以真正的控制器成员变量用得很少,对它们做一定的区分,那是有必要的。

PHP语法自由,要做到某种效果,有非常多的方法,没有什么不可能的。

不过作为一个框架,更重要的是给出一个能促进良好编程习惯的规范,而不是给出一个什么都有的大杂烩。

这个也是经过很长时间的考量才得出来的,并不是没有认真考虑过。

2013-04-04 18:33:45

#11 stalker

ok  仔细想来这样也有道理  不纠结了  :lol

2013-04-05 05:05:41