Yii Framework Forum: Class Level Methods vs Static Methods - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Class Level Methods vs Static Methods What are Class Level Methods and how to use them Rate Topic: ***** 6 Votes

#1 User is offline   Sheldmandu 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 42
  • Joined: 01-April 10
  • Location:Brisbane, Australia

Posted 22 December 2010 - 11:48 PM

*
POPULAR

It seems that many developers are a little confused with the use of what in Yii is referred to as Class Level Methods and don't understand how to use them as opposed to Static Methods. For example people write Comments::generateTags() instead of Comments::model()->generateTags(). This is understandable, given how little guidance is given on this... Here's the more detailed guidance. What Class Level Methods are are effectively Static Methods BUT with the benefit of being able to use inheritance. That is, you can override the operation of a Class Level Method in a subclass, whereas if you used a static method you would not be able to override it. Much of the confusion actually comes from the fact that you're putting something that acts on the recordset (as opposed to on an individual record) as a non-static method of an active record class and it just feels weird, so you drop back to using a static method. Usually, what one would do is if they wanted to create methods to act on the recordset rather than the individual record (and have the benefit of inheritance) is to create a Manager/Module class which is responsible for operations on sets of records. For example CommentManager/CommentModule (note that module is not used in the sense that Yii uses it but in the sense that Martin Fowler uses it when describing Table Module pattern). As Martin Fowler points out on on p. 127 of his book called Patterns of Enterprise Application Architecture, the benefit of an instance is inheritance. Effectively what the designers of Yii have done is rolled this all into the one ActiveRecord class. So it might feel a little weird at first, but then you get used to it. So, in general, you should use class level methods, not static methods, as it gives you the benefit of inheritance although it might feel a little weird. Then you call them using $class::model()->method(). Hope this helps developers understand how to structure their code.

I've also added this info to the Difinitive Guide to Yii on the page that explains AR.
10

#2 User is offline   qiang 

  • Yii Project Lead
  • Yii
  • Group: Yii Dev Team
  • Posts: 5,879
  • Joined: 04-October 08
  • Location:DC, USA

Posted 23 December 2010 - 12:30 AM

Very nice explanation! Thanks.
0

#3 User is offline   yes.yii 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 25
  • Joined: 31-July 09

Posted 01 February 2011 - 07:47 AM

In general,using $class::model()->method() would benefit from inheritance although it might feel a little weird.
0

#4 User is offline   yes.yii 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 25
  • Joined: 31-July 09

Posted 02 February 2011 - 02:31 AM

refer to the source code

public static function model($className=__CLASS__)
{
    if(isset(self::$_models[$className]))
        return self::$_models[$className];
    else
    {
        $model=self::$_models[$className]=new $className(null);
        $model->_md=new CActiveRecordMetaData($model);
        $model->attachBehaviors($model->behaviors());
        return $model;
    }
}


who can analyse this further.
0

#5 User is offline   krowe 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 26
  • Joined: 27-September 12
  • Location:Peoria IL, USA

Posted 23 August 2013 - 01:07 PM

Since I've started using Yii I've always accepted this explanation but today I'm documenting some of my code and I wanted to be sure I had the wording just right on what exactly this method does. I began by looking this post up again and the phrase, "...you can override the operation of a Class Level Method in a subclass, whereas if you used a static method you would not be able to override it." kept getting stuck in my head because I was sure that was not the case. It may have once been the case but it is no longer true. To ensure that I was not incorrect, I've made a test file to show that this is indeed not the case:

<?php
define('BUBBLE', true);

class BaseClass {
	/** This was taken from Yii CActiveRecord class (with the irrelevant parts removed for simplicity). */
	public static function model($className=__CLASS__) {
		$model=new $className(null);
		return $model;
	}

	/** This just formats the output a little nicer. */
	public static function rpt($msg, $this_exists) { echo "<p class=fun>$msg() called; \$this <b>does".($this_exists?'':' not')."</b> exist</p>\n"; }

	public static function staticTest() { BaseClass::rpt('BaseClass::staticTest', isset($this)); } 
	public function instanceTest() { BaseClass::rpt('BaseClass::instanceTest', isset($this)); } 
}

class MidClass extends BaseClass {
	public static function model($className=__CLASS__) { return parent::model($className); }

	public static function staticTest() { BaseClass::rpt('MidClass::staticTest', isset($this)); if(BUBBLE) parent::staticTest(); } 
	public function instanceTest() { BaseClass::rpt('MidClass::instanceTest', isset($this)); if(BUBBLE) parent::instanceTest(); } 
}

class UndefinedClass extends MidClass {
	public static function model($className=__CLASS__) { return parent::model($className); }
}

class FinalClass extends UndefinedClass {
	public static function model($className=__CLASS__) { return parent::model($className); }
	
	public static function staticTest() { BaseClass::rpt('FinalClass::staticTest', isset($this)); if(BUBBLE) parent::staticTest(); } 
	public function instanceTest() { BaseClass::rpt('FinalClass::instanceTest', isset($this)); if(BUBBLE) parent::instanceTest(); } 
}

class NewerClass extends FinalClass {
	public static function model($className=__CLASS__) { return parent::model($className); }
	
	public static function staticTest() { BaseClass::rpt('NewerClass::staticTest', isset($this)); if(BUBBLE) parent::staticTest(); } 
	public function instanceTest() { BaseClass::rpt('NewerClass::instanceTest', isset($this)); if(BUBBLE) parent::instanceTest(); } 
}

?><!DOCTYPE html>
<html lang=en-US>
<head>
	<meta charset=UTF-8>
	<title>Model Tests</title>
	<style>
		p.fun {padding-left:25px;}
	</style> 
</head>
<body>
	<h1>Model Tests</h1>
<?php

echo "<h3>Final Class -- Static Method Test without model()</h3>\n";
FinalClass::staticTest();

echo "<h3>Final Class -- Static Method Test with model()</h3>\n";
FinalClass::model()->staticTest();

$testClass=new FinalClass;
echo "<h3>Final Class -- Instance Method Test without model()</h3>\n";
$testClass->instanceTest();

echo "<h3>Final Class -- Instance Method Test with model()</h3>\n";
FinalClass::model()->instanceTest();

echo "<h3>Undefined Class -- Static Method Test without model()</h3>\n";
UndefinedClass::staticTest();

echo "<h3>Undefined Class -- Static Method Test with model()</h3>\n";
UndefinedClass::model()->staticTest();

$testClass=new UndefinedClass;
echo "<h3>Undefined Class -- Instance Method Test without model()</h3>\n";
$testClass->instanceTest();

echo "<h3>Undefined Class -- Instance Method Test with model()</h3>\n";
UndefinedClass::model()->instanceTest();

?>


If you were to play with this code you'd find out that no matter how you call these methods they ALL work exactly the same except that (as expected) the $this variable exists in only in the instance methods.

It is possible that providing a $this variable is the true purpose of this method but (as the OP has mentioned already) it shouldn't be needed at all for the methods which use model() because those are methods which work on the dataset instead of working with an individual record.

Is there another reason that this method is needed? Has it been made obsolete by a PHP update (and is therefore only needed for compatibility)?

(BTW: I'm using PHP 5.4.9-4ubuntu2.2)
0

#6 User is offline   krowe 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 26
  • Joined: 27-September 12
  • Location:Peoria IL, USA

Posted 23 August 2013 - 01:28 PM

I see now, this method was implemented as a hack to work around the fact that at some point Late Static Binding had not yet been implemented. Apparently, if you use PHP 5.3+ you should be able to safely quit using these methods. One caveat would be that if you use a module or extension which uses this you may run into problems.
0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users