emlog的日志别名功能

emlog3.3的版本就给自己这个博客弄了日志别名(自定义URL)的功能,因为感觉这功能对seo很重要。后来更新到3.5.2也把这功能同步过去了。

emlog日志别名功能效果图1

emlog日志别名功能效果图2

看了下emlog的新版本4.0的新功能点,貌似也支持日志别名功能了,还有其他挺多的,目前没有升级的打算。昨天在官方博客那边说了下挺多人来问如何实现日志别名功能的,这里简单描述下。

弄emlog的日志别名功能先给数据库blog表添加一个字符串类型的字段url。借助的是Google的翻译接口,站里另外骗文章有这东东:js-使用google翻译接口API

关键代码下载:emlog开发日志别名自定义URL功能代码下载

另外还要配合.httaccess的解析或者通过index.php唯一入口对请求的url进行路由转换。

自从使用emlog以来,数数算算,自己添加的功能也多的。

最早的emlog标签球获取热门100条,根据叨叨的话添加随机标题后缀,日志自定义URL,自定义Page页面,热门日志功能,网站xml地图功能,网站标签库,面包屑,重新整理文章归档,日志相关文章推荐,文章关键字提取,评论列表的gravatar头像,评论发信通知博主,回复通知留言者,网站在线群聊等等。。

这些效果看图片:

emlog热门日志功能

emlog热门日志功能效果图

emlog网站xml地图功能

emlog网站日志功能效果图

emlog网站面包屑功能

emlog网站面包屑功能效果图

emlog文章归档

emlog文章归档效果图1

emlog归档效果图2

emlog日志相关推荐文章功能

emlog日子相关推荐功能效果图


emlog评论列表gravatar头像功能

emlog评论列表gravatar头像效果图

emlog在线群聊功能

emlog多人在线群聊功能

Python为什么要self

接触Python以来,看到类里的函数要带个self参数,一直搞不懂啥麻子原因。晚上特别针对Python的self查了一下,理理。

Python为什么要使用self的原因

Python要self的理由

Python的类的方法和普通的函数有一个很明显的区别,在类的方法必须有个额外的第一个参数
(self
),但在调用这个方法的时候不必为这个参数赋值
显胜于隐
的引发)。Python的类的方法的这个特别的参数指代的是对象本身,而按照Python的惯例,它用self来表示。(当然我们也可以用其他任何名称来代替,只是规范和标准在那建议我们一致使用self)

为何Python给self赋值而你不必给self赋值?

例子说明:创建了一个类MyClass,实例化MyClass得到了MyObject这个对象,然后调用这个对象的方法MyObject.method(arg1,arg2)
,这个过程中,Python会自动转为Myclass.mehod(MyObject,arg1,arg2)

这就是Python的self的原理了。即使你的类的方法不需要任何参数,但还是得给这个方法定义一个self参数,虽然我们在实例化调用的时候不用理会这个参数不用给它赋值。

实例:

class Python:
 def selfDemo(self):
  print 'Python,why self?'
p = Python()
p.selfDemo()

输出:Python,why self?

把p.selfDemo()带个参数如:p.selfDemo(p),得到同样的输出结果

如果把self去掉的话,

 

class Python:
 def selfDemo():
  print 'Python,why self?'
p = Python()
p.selfDemo()

这样就报错了:TypeError: selfDemo() takes no arguments (1 given)

扩展

self在Python里不是关键字。self代表当前对象的地址。self能避免非限定调用造成的全局变量。

在Python3之后不知道将self隐了没?感觉在Python类里的方法都要带个self这样有点死板

Magento SEO优化

1. 基本的技术优化
1.1. 普通设置
Magento 是搜索引擎最友好的商用平台之一,但有几点需要关注以优化你的 Magento SEO. 第一步是使用最新的版本, 1.2.1. 然后,开始运行时,激活 Server URL rewrites. 你可以找到这个选项在系统按钮下: System => Configuration => Web => Search Engines Optimization. 激活后,在这个页面上,另一个不错的选择是设置“Url Options ”下的 "Add store Code to Urls" ,在大多数情况下,把这个开关设为“No”更好。

1.1.1. WWW vs non-WWW
在 "Unsecure" 和 "Secure" 的下拉菜单里你可以找到 Base URL, 在那里你可以设置你更喜欢的域名。你可以选择WWW的URL或者没有WWW的URL。改变这些设置你不会建立一个重定向从www到non-www或者从 non-www到www,而只是你设置的你喜欢的那一个。所以通过 .htaccess with mod_rewrite建立一个301重定向是一个好主意。除此之外,解决了 WWW vs non-WWW 的问题,这个重定向可以预防Magento被加入SID问题到你的URLs, 象?SID=b9c95150f7f70d6e77ad070259afa15d. 确保 Base URL 和重定向是一样的。编辑 .htaccess 文件时,你可以加入下面的代码到根目录下的重定向 index.php 中。

大约 119 行:

RewriteBase / RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/
RewriteRule ^index\.php$ http://www.sjolzy.cn/ [R=301,L]
或者,你安装Magento的时候不是在根目录下而是在某个子目录下http://www.sjolzy.cn/magento/:

RewriteBase /magento/ RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /magento/index\.php\ HTTP/
RewriteRule ^index\.php$ http://www.sjolzy.cn/magento/ [R=301,L]
1.2. 页眉设置
安装Magento时默认的标题是 "Magento Commerce"。为了你的Magento商店得到它应得得流量,以下你必须了然于胸:

搜索引擎着重于开头的词,所以如果你的关键字靠近页面标题的开头那你有更大的可能性让排名更好。
人们扫视结果页面,一般看开头的几个词。如果你的关键字位于页面的的开始,那你被点击的可能性就大很多。
首先你应该去掉默认的标题 "Magento Commerce". 后台点击 Configuration => Design => HTML Head. 为你的网站选一个描述性好的标题,这个标题也会在几个没有内容的页面中使用,比如 "Contact Us" 和 "Popular Search Terms".

把页面标题加到你的店名中,包括目录和商品,把你的店名放在“标题后缀”中。保持前缀空白是个不错的选择,原因上面提到过。同时保持 "Default Description" 和 "Default Keywords" 空白。对于非产品展示页面,为防止整站索引,设置 "Default Robots" 为 "NOINDEX, NOFOLLOW" 会有所帮助,但对于别的页面来说要确保设置为 "INDEX, FOLLOW".

现在我们优化你的网店页面的 <head> ,好的方法是加上 new canonical tag (新的规范标签)。你可以安装 Canonical URL's for Magento Module 以便把它们加到你的head种来改进你的Magento SEO。

因某些原因Magento把未设置的meta机器人转为一个meta标签,方式如下:

<meta name="robots" content="*" />
这种方式会造成搜索引擎一些奇怪的行为,所以我们要把它移除。要从代码中移除这些空白的meta你可以安装 Yoast MetaRobots Module.

1.3. CMS 页面
第一眼看上去Magento似乎缺少华丽的CMS功能,但对于大多数使用者来说这已经足够了。简单的CMS的好处之一是你能够控制页面的每一个方面。一旦 你赋予每一个CMS页面一些不错的内容,选一个SEF URL鉴别者和页面标题,(同时记住1.2小节中的要点),到Meta数据标签处为每个你想要给它排名的CMS页面写上描述。

你可以保持"Keywords"栏空白。描述有一个很重要的作用:引诱人们去点击,所以确保它描述的确实是他们所要点击页面的内容,那样可以引起他们的注 意。因此,唯一的好的描述就是自己手写的,如果你考虑用自动描述软件来写描述,那还不如什么也不做,让搜索引擎负责这部分。

如果你不使用meta描述,搜索引擎会在你的文件里找到关键字,并自动选择一条,那样在结果页面里会有一到两个醒目的词。

1.4. 商品目录优化
Magento 给你增加目录名的权利,让你的目录指向产品的URL。因为Magento对建立相同的内容这个功能的支持不够,很好的方式就是禁用它。设置它,点击 System => Configuration => Catalog => Search Engine Optimization and set "Use categories path for product URL's to "no".

现在是时候设置每一个目录的细节了。点击Catalog => Manage Categories. 最重要的区域是:

Meta 描述: 在这里放上吸引人的描述;记住人们会在搜索引擎的结果列表页中看到这个描述。
页面标题: 保持页面标题空白,使用目录名包括父目录。但你按照要求制作目录时,标题会象你所输入的一样,没有父目录。
URL 要点: 尝试保持短的但是关键字丰富的URL。移除没用的词象“the”,“and","for"等等。要注意的是你只能在“all store views”下设置, 对于多语种的商店你应该保持语言的独立。
对于每一个商店界面,你可以指定名字,描述,页面标题和Meta数据。对多语种商店来说这真的是一个很棒的功能。

1.5. 商品优化
商品页面的优化和目录优化有些相似。你可以设置Meta信息为 "Default Values" 并使用于每一个 "Store View". 注意对于 "Meta Title", 这个将写在完全的页面标题上,包括目录但不包括标题的前缀/后缀,而不仅仅是商品的名称。

Magento SEO中一个经常忽略的方面是你怎么处理你的图片。通过给图片写标签和考虑给你的图片起怎样的名字,你会从不同的图片搜索引擎得到不错的额外流量。

2.Magento模板优化
2.1. 优化了的空白模板
默认的Magento皮肤如 "Default Theme", "Blue Skin" 和 "Modern Theme" 在标题方面的工作做得不好,从SEO的角度来看,有很多的地方可以改进。为使它对你变得简单,我们开发了一款空白的Magento SEO模板,基于Magento的核心技术,空白模板合并了所有的东西,你可以下载并一起讨论它 download and discuss it here.

2.2. 标题
默认的 logo 是一个 <h1>, 应该只是出现在首页,在别的页面上它应该是一个<h3>. 最重要的事实让标题的内容置于 <h1> 标签之中,例如,在目录页它应是目录名在商品也应是商品名。

下一步是清除过量的标题。一个好主意是清除侧栏的标题,或者做一个和商店相关的文字(包括关键字)。没有什么理由加上"static" 和没有什么关键字的标题在<h4>中. 是的,例如,把所有的 <h4> 标签换成 <div> to <strong> 标签更好。现在是时候优化你的内容了,在目录页中把商品名放在 <h3> 里,把目录名放在 <h1>里。在商品页,你应该把商品名放在<h1>里.

想了解更多关于为什么正确的标题是重要的,可以阅读这篇文章 Semantic HTML and SEO.

2.3. 清除你的代码
保持你的模板清爽,把你的模板文件中的所有 javascript 和 CSS 移到外部的 javascripts 和css 文件中,因为它们对你的Magento SEO没有任何好处。这样做可以确保你的用户在首次读取文件的时候储存那些文件,搜索引擎不需要花费大量的时间来下载它们。

2.4. 速度辅助
一个很重要的情况是搜索引擎每一天要在你的商店爬过多少页面,你的商店的读取速度有多快。

你可以做两件事来增加你的Magento的速度:

激活缓存。后台点击 System => Cache Management and enable all caching features, like this.
一个号的主机和服务器的设置也是很重要的。用 MySQL 和 PHP opcode 缓存你可以戏剧性的提高你的Mageto速度。
另一件需要考虑的二十外部文件的数量。每一个你让人们下载的文件,他们的浏览器会建立另一个连接到网络服务器。所以非常好的主意就是减少外部文件的数量,合并几个文件为一个文件。默认的Magento已经合并了几乎所有的 javascript 文件到一个文件中。

但 stylesheets 文件没有合并:默认模板有6个不同的stylesheet 文件。你可以把这些文件合并成一个新文件,除了print.css文件,或者你可以使用这个 Fooman Speedster module. 除了合并文件外,这个模数能压缩和缓存你的 javascript 和 stylesheet 文件。 (请注意Speedster的使用条件: mod_rewrite 必须可用,你的服务器需要支持.htaccess。  如果你在Magento同时使用规范的URLs和 Fooman Speedster,你需要利用this download在Canonical module 上写。

3. 高级的Magento SEO 和相同的内容
一旦你完成了所有基础的东西你会发现剩下的事情就是一件简单的事:相同的内容。实际上是大量的相同的内容。商品里有相同的内容,至少,在下面的URLs有完全相同的内容:

domain.com/product.html
domain.com/category1/product.html
domain.com/catalog/product/view/id/1/
domain.com/catalog/product/view/id/1/category/1/
此外,商品回顾页面有几乎一样的内容。另一个问题是目录,你有大量相同的内容在层级导航中和索引选择中。最坏的情况是一个商品在这个页面显示之外,至少还会在这个页面以外的4个页面中显示。

我们将要去掉这些相同的内容,并允许它们被蜘蛛爬但不被索引,固定目录的索引选择和层级导航。

3.1. 无内容页面的Noindex, follow
安装 Yoast robots meta module 并确保设置成防止索引所有的无内容页面,如下:



现在搜索引擎将通过所有的链接来到这些页面上但不会再索引中显示这些页面。

3.2. Nofollowing 非必需的链接
另一简单的步骤来提高你的 Magento SEO 是停止链接到你的登录,付款,希望购买列表和所有其他没有内容的页面。对于RSS feeds,层级导航,增加商品到希望购买列表,增加商品到比较列表来说也是同样的设置。目前还没有插件来完成这些工作。你不得不进入你的模板文件中手工 完成。

3.3. 规范的URLs
帮助搜索引擎理解你页面中的相同内容,你可以在每个页面使用你更喜欢的URL,使用新的 canonical URL tag (规范的URL标签),你就应该安装这个 Canonical URL's for Magento 模数。

3.4. XML 地图
XML 地图是让搜索引擎知道你的内容在哪里的简单方法,它不会帮助你提高排名,但它可以帮助你更快得到索引。你可以手工建立一个XML地图,后台点击 Catalog => Google Sitemap => Add Sitemap, 选择一个文件名,路径和商店界面,然后点击 "Save & Generate"。

然后你可以简单的把下面的代码放到你的 robots.txt 文件中指引搜索引擎向你的 sitemap.xml 文件:

Sitemap: /sitemap.xml
完成了这些修改,你重新获得XML地图。要确认它们是最新的,最好的办法就是建立一个cron工作,更广泛的描述的过程看这里 here.

结尾:Magento SEO的发展
这篇文章涵盖了Magento SEO的所有方面,如果你有任何的反馈,或者有附加意见, let us know, 我们就可以改进这篇文章。我们和Magento核心开发组一起工作来提高Magento SEO的各个方面,我们正试图通过这篇文章得到一些想法和建议可以用到Magento的核心中去。
 

osc站常见问题解决(持续更新)

1.新增产品后的导航栏
首页:include/header.php  关键字:nav_top
                    <li><a href="/Accessories/Du-Rag.html"><b>Accessories</b></a></li>
                    <li><a href="/Fan-Shop/Atlanta-Hawks.html"><b>FAN SHOP</b></a></li>
                    <li><a href="/Men/Nike-Vandal-Low.html"><b>MEN</b></a></li>
                    <li><a  href="/Women/Air-Jordan-V.html"  ><b>WOMEN</b></a></li>
                    <li><a  href="/Kids/AIR-MAX-90.html" ><b>KIDS</b></a></li>
                    <li><a href="/new_arrival.php" ><b>NEW ARRIVALS</b></a> </li>

产品页:include/html_header.php  关键字:nav_top
                    <li><a href="/Accessories/Du-Rag.html"><b>Accessories</b></a></li>
                    <li><a href="/Fan-Shop/Atlanta-Hawks.html"><b>FAN SHOP</b></a></li>
                    <li><a href="/Men/Nike-Vandal-Low.html"><b>MEN</b></a></li>
                    <li><a  href="/Women/Air-Jordan-V.html"  ><b>WOMEN</b></a></li>
                    <li><a  href="/Kids/AIR-MAX-90.html" ><b>KIDS</b></a></li>
                    <li><a href="/new_arrival.php" ><b>NEW ARRIVALS</b></a> </li>


2.新增产品传递尺码问题
首先在后台Catalog - Products Attributes - Option Values 添加Gender属性,值为新增的一级目录名
然后make_product_list.php604行左右修改,
<input name="id[3]" value="27" id="id[3]" type="hidden"> //id[]里的数字为该产品系列的Product Options Id,value为该产品所属父级Option Values 的id
<select size="1" name="id[3]" id="id[3]"> //这边的id[]要对应上面数字。
接着修改include/application_top.php 402行左右。
if($HTTP_POST_VARS['id'][2]==0 and $HTTP_POST_VARS['id'][7]==0)改为:
if($HTTP_POST_VARS['id'][2]==0 and $HTTP_POST_VARS['id'][7]==0 and $HTTP_POST_VARS['id'][8]==0 and $HTTP_POST_VARS['id'][9]==0)

 

2010年最新PHP类的精缩归纳

 

一:结构和调用(实例化):

 

class className{} ,调用:$obj = new className();当类有构造函数时,还应传入参数。如$obj = new className($v,$v2...);

 

二:构造函数和析构函数:

1、构造函数用于初始化:使用__construct(),可带参数。

2、但析构函数不能带参数(用于在销去一个类之前执行一些操作或功能)。析构函数用__destruct()做名称。在脚本执行结束时,PHP会销掉内存中的对象,因此可不用析造函数,但有些比如COOKIE等,就应当要用此函数销掉。

知识点:在PHP4中也提供了构造函数,但使用的是与类同名的类方法,在PHP5仍能兼容这种做法,当一个类中没有包含__construct时,会查找与类同名的方法,如果找到,就认为是构造函数,如下:

class test

{ var $b;

function test() {   $this->b=5; }

function addab($c) {   return $this->b+$c; }

}

$a = new test();   echo $a->addab(4); // 返回 9

3、PHP不会自动调用父类的构造函数(不支持构造函数重载),必须使用parent关键字显式地调用。

class employee{

      function __construct()....

}

class Manager extents Employee{

     function __construct(){

          parent::_construct();

          echo '这个子类的父类构造函数调用了!';

     }

}

当然也可以调用与该实例没有任何关系的其它类的构造函数。只需在__construct()前加上类名即可。如:

otherClassName::__construct();

 

类的主家庭成员:属性、方法、常量、静态成员

 

三、类的属性:

有两种方法对类的属性赋值或取值。

1、使用公共作用域public关键词。

2、使用__set()和__get()来分别赋值和取值,前者称为设置方法(setter)或修改方法(mutator),后者称为访问方法(accessor)或获取方法(getter)。建议使用这种方法:优点:

A、可在__set()统一进行数据验证。

B、便于统一管理属性。

注意:

第一:__set()和__get()只对私有属性起作用,对于用public定义的属性,它们两个都懒理搭理,如下:

class test{

protected $a=9,$b=2,$c;

   public $d;

    function __set($n,$v) {    $this->$n = $v+2; }

    function __get($name) { return $this->$name+2; }

}

$a = new test();

$a->b =5; echo "<br />";   echo $a->b;

实例只对$a,$b,$c的设置会经过__set和__get过滤与返回,对于$d,就不会起作用。如$a->d=5,再返回还是5。

第二:__set($n,$v)要带两个参数。而__get($n)只能有一个参数。实例:

class test{

      private $a=5,$b=6,$c;

      function __set($n,$v)

     {

        if($n=='a'&&$n>0)

               $this->$n = $v;

         else

               $this->$n = $v+2;     

     }

      function __get($name)

      {

            return $this->$name; //如果改为return $this->$name + $this->addab();   如调用a的值,实际返回的是a+a+b的值。默认为5+5+6=16。

      }

      function addab()

       {         return $this->a + $this->b;   }

}

$e=new test();

$e->a = 11;   //注意写法:类的内部用$this->$n即变量的写法,但外部实例要用$e->a的方式。

$e->b = 12;   //get 14

$e->k = 22;

 

类的属性可自由扩展,如上例的k,不管是否用__set,当一个实例建立起来后,可以用$e->newProperty = xx;直接来创造一个属性,但不建议这么做。

 

四、类的方法:

理解成类当中的函数即可。

调用:

1、内部调用:可使用$this->Fanname();或$this->addab()或test::addab();

2、实例化调用时,用$e->addab();即可。对于在该方法中没有使用$this关键字的,如上例中的:

function addab() {    return $this->a+$this->b;    }

改为: function addab() {    return 25;    }那在在外部实例调用该方法,也可用“$e::addab();”或“test::addab();”

 

五、类的常量:

如果类的属性理解成类中的变量,那么类的常量和变量是不一样的,其定义方法为:

class test{

      private $a;

      const PI = '3.14';

      .....

      //在类中调用上面的常量用两种方法,“$this::PI”,或 “类名::PI”,这里就是test::PI,如下:

      function getvalue(){

            return $this->a * $this::PI; //或$this->a * test::PI,用this关键字或类名均可,但都要用双冒号。

     }

}

$e= new test();

$e->PI =5;   //注意,这里用 ->只是创造了一个也是名为PI的属性,而不是改变类中的PI常量的值。

echo $e::PI; //这个才是调用类的常量。

常量只能用双冒号::来调用。并且不能更改其值。

在类外部实例化后调用类常量同样也有两种方法。方法为:

“$e::PI”   或 “test::PI”,共同点是都要用冒号,不同点是外部不能用this关键字,只能用实例名,但类名::PI是通用的。

 

六、类的静态成员(静态属性或静态方法):

如果需要创建供所有类的实例共享的字段或方法。就得用静态成员。有两个特征:

1、静态成员是共产主义者,它让脚本上的所有该类的实例调用,但不能借助类的特定实例名调用,而是在类的外部,统一使用“类名::$成员名”的方式调用。而类的内部则统一使用 “self::$成员名”来调用。

2、当每一次新创建实例时,静态成员会从上次创建的实例最后值开始重新计算,而不是类中初始的值开始计算。

3、对于用public定义的静态成员,可以在外部更改它的值。private等则不行。

class test{

       public static $v = 0;

    function __construct(){  self::$v++; }

    static function getV(){   return self::$v; }

}

$a = new test();

echo test::getV(); // 返回 1

$b = new test();

echo test::getV();   // 返回 2

test::$v=8;   //由于public定义的成员,改变静态成员的值。

$c = new test();

echo test::getV();   // 返回 9

 

七、关键字:

(一)this关键字:用于类的内部指代类的本身。来访问属性或方法或常量,如$this->属性名或方法名。$this::常量名。this还可以用在该类的子类中,来指代本身的属性或方法。

(二)双冒号“::”关键字:用于调用常量、静态成员。

(三)self关键字:在类的内部与双冒号配合调用静态成员,如 self::$staticVar.,在类的内部,不能用$this来调用静态成员。

(四)__toString():在类中使用__toString(),用于将类转成字串并打印类,用处不大:如:

class test{     public $p;

   public function __toString(){   return var_export($this,TRUE);   }

}

$a=new test();

echo $a; //输出:test::__set_state(array( 'p' => NULL, )),或写成:echo $a->__toString();

(五)__clone() :当克隆对象时,这个关键字才会发生作用,用于更改克隆时某些值。

(六)__call():方法重载,参下面示例:

class cB{

function __call($method,$n){

    if($method=='showVarType'){

        if(is_numeric($n[0])){   //不能用$n。要用$n[0];

                $this->displayNum();

           }else if (is_array($n[0])){

                $this->displayArr();

         }else{

                $this->displayOther();

        }

   }

}

function displayNum() {

        echo '<h3>这是数字!</h3>';

}

function displayArr() {

      echo '<h3>这是数组!</h3>';

}

function displayOther() {

      echo '<h3>不是数组也不是数字!</h3>';

}

}

 

$x='a';

$y=array('a','b');

$b=new cB;

$b->showVarType($x); //不是数组也不是数字

$b->showVarType($y); //这是数组

注意,不能在类中定义showVarType()方法,否则代码不能用。

(七)extends:继承: 如class a{}     class b extends a{} 类b继承了类a

 

 

附:记忆:以后统一在调用方法或属性时用 "-> ",调用常量则用双冒号“::”,不会搞晕。

 

八、方法和属性的作用域:

共有6种:public(默认,可省略,也等同于php6的var声明),private(私有,也不能由子类使用),protected(私有,但可由子类使用) ,abstract(抽象,参下文),final(阻止在子类中覆盖—也称重载,阻止被继承,用于修饰类名及方法,如final class test{ final function fun(){}} ,但不能用于属性),static(静态)

 

九:抽象类和抽象方法(abstract——注意:没有所谓抽象属性):

抽象可以理解成父类为子类定义了一个模板或基类。作用域abstract只在父类中声明,但在子类中实现。注意事项:

1、抽象类不能被实例化,只能被子类(具体类)继承后实现。

2、抽象类必须在其子类中实现该抽象类的所有抽象方法。否则会出错。

3、在抽象方法中,只是声明,但不能具体实现:如abstract function gettow(){ return $this->p; }是错的,只能声明这个方法:abstract function gettow();(连方括号{}都不要出现),抽象方法和抽象类主要用于复杂的类层次关系中。该层次关系需要确保每一个子类都包含并重载了某些特定的方法。这也可以通过接口实现

4、属性不能被命名为抽象属性,如abstract $p = 5是错的。

5、只有声明为抽象的类可以声明抽象方法,但如果方法声明为抽象,就不能具体实现。如:

abstract class Employee

{

    abstract function a(...);

    abstract function b(...);

}

以后再对这个父类扩展,组成各种子类(如经理,员工,出纳)。

6、抽象类中,如果要实现具体的方法,不能声明为抽象。这样可能实际意义更大。可以把几个类库中共同的部分提取到抽象类中,其它的类继承抽象类即可。如下:

abstract class BaseShop{

     Const TAX=0.06;    // 在抽象类中定义常量

    public function buy($gid) {     // 如果定义为抽象方法abstract function buy()就不能在这里实现主体。

         echo('你购买了ID为 :'.$gid.'的商品');

   }

      public function sell($gid) {

      echo('你卖了ID为 :'.$gid.'的商品');

      }

     public function view($gid) {

       echo('你查看了ID为 :'.$gid.'的商品');

     }

}

class BallShop extends BaseShop{

     var $itme_id = null;

     public function __construct()

    {

          $this->itme_id = 2314;

     }

     public function open()

      {

         $this->sell($this->itme_id);

     }

      public function getTax()

     {

              echo printf('<h3>平均税率是 %d%%。</h3>',$this::TAX*100);

      }

}

$s = new BallShop;

$s->open(); //你卖了ID为 :2314的商品

$shop->getTax();

 

十:类型提示:

注意,类型提示功能只能用于参数为对象的提示,而无法用于为整数,字串,浮点等类型提示。有些类的方法需要传入的参数为所期望的对象类型,可以用下面的方法达到强制实施此替则。要达到类型提示,只要在方法的对象型参数前加一个已存在的类的名称,如:function funname(OtherClassName $otherclassINSName,$c....),注意,OtherClassName必须是存在的类。如下:

class em{   var $k=56; }

class test{

function __construct()

{   echo $this->addab(new em(),2);   }

function addab(em $j,$c)   //这个方法,即可以在内部调用,也可以在外部调用。只要作用域许可。

{    return $j->k+$c; }

}

$a = new test();

$b = new em();

echo $a->addab($b,2); //或 $a->addab(new em(),2);

 

十一、类的管理:

1、instanceof关键字:用于分析一个对象是否是某一个类的实例或子类或是实现了某个特定的接口:如下例,但要注意: 类名没有任何引号等定界符,否则会出错。如test不能用'test'

class test2{}

class test{}

class testChilern Extends test{}

$a = new test2();

$m = new test();

$i = ($m instanceof test);

if($i)echo '$m是类test的实例!<br />'; // get this value

switch ($a instanceof test){

   case true :

           echo 'YES<br />';

            break;

    case false :

            echo 'No<br />';   //get this value

    break;

}

$d=new testChilern();

if($d instanceof test)echo '$d是类test的子类!<br />'; // get this value

2、确定类是否存在:boolean class_exists(string class_name): class_exists('test');

3、返回类名:string get_class(object),成功时返回实例的类名,失败则返回FALSE:

$a = new test2(); echo get_class($a);   //返回 test2

4、了解类的公用属性:array get_class_vars('className') ,返回关键数组:包含所有定义的public属性名及其相应的值。这个函数不能用实例名做变量

5、返回类方法:get_class_methods('test'); //或: get_class_methods($a);可用实例名做参数,返回包括构造函数在内的所有非私有方法。

6、print_r(get_declared_classes())了解当前PHP版本中所有的类名。PHP5有149个。

7、get_object_vars($a)返回实例中所有公用的属性及其值的关联数组。注意它和get_class_vars()的区别:

/* (1) get_object_vars($a)是用实例名做参数,而get_class_vars('test')是用类名做参数。

* (2) get_object_vars($a)获得的属性值是实例运行后的值,而get_class_vars('test')获得的属性值是类中的初始定义。

* (3) 两者均返回关联数组,且均对未赋值的属性返回NULL的值。如类test中有定义了public $q;则返回Array ( [v] => 5 [q]=>) ,

*/

8、返回父类的名称:get_parent_class($b);//或get_parent_class('test2'); 返回test

9、确定接口是否存在:boolean interface_exists($string interface[,boolean autoload])

10、确定对象类型: boolean is_a($obj,'className'),当$obj属于CLASSNAME类时,或属于其子类时,返回TRUE,如果$obj与class类型无关则返回FALSE。如:is_a($a,'test')

11、确定是否是某类的子对象:当$b是继承自TEST类时,返回TRUE,否则FALSE。boolean is_subclass_of($b,'test'); 

12、确定类或实例中,是否存在某方法。method_exists($a,'getv') //或用method_exists('test','getv'),此函数适用于非public定义的作用域的方法。

以上函数实例:

class test{

public $v=2;

private $c=5;

function __construct(){

   $this->v=5;

}

private function getv(){

   return $this->v;

}

}

class test2 extends test{}

 

$a=new test();

$b=new test2();

print_r( get_class_methods('test')); //或:print_r( get_class_methods($a)); 均返回:Array ( [0] => __construct [1] => getv )

echo '<br />';

print_r( get_class_vars('test')); //返回:Array ( [v] => 2 ),和上面不一样,不能用print_r( get_class_methods($a));

echo '<br />';

echo get_parent_class($b);//或get_parent_class('test2'); 返回test

echo '<br />';

echo is_a($b,'test');// 返回1

echo '<br />';

if(is_subclass_of('test2','test'))echo '是子类!'; //或(is_subclass_of($b,'test')),返回1,当参数1为$a时则返回false,

echo '<br />';

echo method_exists($a,'getv') //或用method_exists('test','getv')返回1,本函数也适用于用private等定义域的方法。

 

十一、自动加载类库文件:

当类多了以后,比如要在一个文件中载入3个类库文件:a.class.php,b.class.php,c.class.php要用三个require_once('classes/a.class.php);

require_once('classes/b.class.php);

require_once('classes/c.class.php);

可以用PHP5自动加载的功能来处理:在全局应用配置文件中,定义一个特殊的函数__autoload($class)函数(__autoload并不是一个类的方法,只是单独的函数,和类没有关系):

function __autoload($class){

     require_once("classes/$class)

}

该函数放哪没有关系,在创建类实例时,也不必去调用这个autoload函数。PHP会自动完成。但务必注意一点:“在调用页面上创建实例所使用的类名称”、和“被调用的文件名”、以及“该文件中的类的名称”3个必须是一样的。这样就不需要去调用__autoload();如果不一样则必须单独调用__autoload('c');并给它一个文件名前缀。如:

c.class.php文件的代码是:

<?php

class c{

public $m=7;

}

?>这里代码的类名称是c,而文件名也是c,

现在要在index.php调用:

<?php

function __autoload($class){

require_once "$class.class.php";

}

 

$m = new c(); //创建实例调用的类也是c

echo $m->m;

?>

此时PHP会自动调用根目录下的c.class.php中的类C。

 

但如果c.class.php中的代码是:

<?php

class mm{

public $m=7;

}

?>

而调用页index.php代码是:

<?php

function __autoload($class){

require_once "$class.class.php";

}

# __autoload('c'); //如果不加这一行就会出错。

$m = new mm(); 

echo $m->m;

?>

会出错,提示找不到mm.class.php文件。这时可以加一行__autoload('c');但这样就达不到简化代码的目的。

 

类的家族化扩展:类的高级功能:

 

一、对象克隆:

当克隆一个对象的实例时,其属性初始值继承了被克隆对象的当前值。

class test

{

public $p=5;

function __clone(){    //只在克隆发生时起作用。用于改变在克隆时某些值

         $this->p=15;   

   }

}

$a=new test();

echo $a->p;

$a->p=8; //如果没有__clone()方法影响,$b的P值将为8

$b = clone $a;

echo $b->p; //15

 

二、对象继承:

 

没有被声明为final的类可以被继承,没有被final和private界定的方法也可以继承,没有被private界定的属性也可以继承。当子类继承了父类或超类后,可以直接使用父类或超类(祖父类以及祖父的祖父)的所有允许的方法,属性。

关键:理解构造函数和重载在继承中的特性!

(一)构造函数在继承中的特性:

1、当父类有构造函数而子类没有:则子类会在实例化时会自动执行父类的构造函数。这时如果要创建子类的实例,需要引入父类构造函数中所需的参数,否则出错。即使是“子类的子类”如果没有构造函数,也要在创建实例时输入其父类的父类的构造函数所需参数。PHP会从实例所在的子类会向上搜索合造的构造函数,一旦找到就停止,使用该构造函数。而不会再向上搜索,因此:子类本身如果没有构造函数,则以其最靠近的一个超类并且有构造函数的为准。

class cA{

public $name,$age;

   function __construct($n) {  

         $this->name = $n;

       $this->age = 25;

}

function __set($n,$v) {

           $this->$n = $v;

   }

function __get($n) {

      return $this->$n;

   }

}

 

class cB extends cA{

   function funB1()   {          echo '<h3>Class cB execute success!</h3>';   }

}

 

class cC extends cB {

function funC1() {     echo '<h3>Class cC FunC1!</h3>'; }

}

$b=new cB('Jack');

$b->name='John';

echo "$b->name : $b->age";

$b->funB1();

$c=new cC(); //这里会出错,由于cB也没有构造函数,因此再向上以cA为准,需要一个参数。改为$c=new cC('David');即可。

echo $c->name(); //David

2、当子类也有构造函数时:这时,不管父类是否有构造函数,都会执行子类自己的构造函数。

如上:

class cB extends cA{

function __construct() {

   echo '<h3>this is Class cB \'s __construct!</h3>';

}

function funB1() {

   echo '<h3>Class cB execute success!</h3>';

}

}

现在类CB有自己的构造函数时,这时创建实例$b=new cB('Jack');参数JACK不会起作用,因为父类CA的构造函数没有得到执行。因此$b->name和$->age就不会初始化值。需要另外赋值$b->name='Jack',$b->age=25;

如果这时要执行父类CA的构造函数,可以这样:

function __construct($n) {

      parent::__construct($n);   // 或:cA::__construct($n);

      echo '<h3>this is Class cB \'s __construct!</h3>';

}

由于parent::__construct($n); 只会向上搜索父类的构造函数,一找到就停止且执行当前找到的构造函数,因此在上面例子中,如果parent::__construct($n)是用在最后一层的类cC中,并且类CB,CA都有构造函数,那么cC的实例只会执行cB的构造函数。不会执行cA。这时,如果CC的实例想都调用CA和CB的构造函数,有两种方法:

A、在CB中也加入parent::__construct($n)

B、在CC中把构造函数改为:

function __construct($n) {

      cA::__construct($n);   //即:类名::构造函数。

     cB::__construct();

echo '<h3>this is Class cB \'s __construct!</h3>';

}

(二)在子类中调用父类的属性或方法:

1、调用父类方法:在子类中调用父类的方法,有3种方法:

     $this->ParentFunction(); 或

   父类名::ParentFunction();    或 

     parent::parentFun();

2、调用父类属性:只能用$this->ParentProperty;

(三)重载:

在子类中,可以定义与父类相同属性或方法,改变父类该属性或方法的值或操作,称做重载。如:

calss ParClass{ function pfun(){ ....}}

class ChildrenClass extends ParClass{function pfun(){ ....}}} //重载了父类的pfun的方法。

在子类中重载后,优先执行自己重载后的新定义的方法或属性。

也可以在子类中用parent::parentFun();调用父类的方法,但所得到的值是子类自己输入的参数运算值。而不是该方法在父类中运算的值。

 

三、接口:

 

接口:interface,可以理解成一组功能的共同规范,最大意义可能就是在多人协作时,为各自的开发规定一个共同的方法名称。

和抽象类中的抽象方法一样:

1、不能在接口中对方法具体实现进行定义。而是由具体类来实现(而抽象类中的非抽象方法可以不必再定义,只有抽象方法和接口是一样要求要在具体类中实现)。

2、和抽象类一样,可以在接口中定义常量,并由具体类直接继承。

3、具体类必须实现抽象类的所有抽象方法(非抽象方法除外),同样,具体类如通过implements实现了接口后,必须完成接口中的所有方法。

 

接口实现过程:1、定义接口,2、用..implement X,Y,...和具体类对接。

interface Info{    //定义接口

     const N=22;

     public function getage();

     public function getname();

}

 

class age implements Info //如要多个接口 class age (extends emJob) implements Info,interB...

{

    public $age=15;

     public $name='Join';

     function getage() {

          echo "年级是$this->age";

     }

      function getname() {

             echo "姓名是$this->name";

      }

      function getN(){

             echo '<h3>在接口中定义的常量N的值是:'.$this::N.' </h3>'; //直接继承接口中的常量值。

     }

}

 

$age=new age;

echo $age::N; //22,直接调用接口中的常量值。

$age->getN();

关于抽象类和接口类的使用区分:何时用接口,何时用抽象?

1、相关性:当创建的模型由一些紧密相关的对象采用时,用抽象。对于不相关对象采用的功能,用接口。

2、多重继承:PHP类可以继承多个接口,但不能扩展多个抽象类。

3、公共行为实现:抽象类可在其中实现公共的方法,但接口不行。

 

四、命名空间(PHP6)

 

类库脚本A.inc.php和脚本B.inc.php中都一个类的名称为 class CNAME,并且这两个文件要在同一个文件如index.php中被调用。这时要用到命名空间。

步聚:

1、打开上面的A和B两个文件,分别在上面的最前面各加一行:

namespace SPACEA;   和 namespace SPACEB;   名字自定。

2、在index.php中实例化类时,在类的前面添加命名空间和双冒号做为前缀:

include 'a.inc.php';

include 'b.inc.php';

$a=new SPACEA::CNAME();

$b=new SPACEB::CNAME();

这样就不会冲突了。

但在PHP6正式发布前,这个功能还未定下来。

 

五、实现迭代器和迭代。

参《PHP圣经》P142;

 

六、使用Reflection(反射)API 。

简易实例: 

class a{ .... }

$c = new ReflectionClass('a'); //PHP 内置类。

echo '<pre>'.$c.'</pre>';

输出类a的结构和内容。参《PHP圣经》P145;

PHPDocument 代码注释规范总结

PHPDocument 代码注释规范

1. 安装phpDocumentor(不推荐命令行安装)
在http://manual.phpdoc.org/下载最新版本的PhpDoc
放在web服务器目录下使得通过浏览器可以访问到
点击files按钮,选择要处理的php文件或文件夹
还可以通过该指定该界面下的Files to ignore来忽略对某些文件的处理。
然后点击output按钮来选择生成文档的存放路径和格式.
最后点击create,phpdocumentor就会自动开始生成文档了。

2.如何写PHP规范注释

所有的文档标记都是在每一行的 * 后面以@开头。如果在一段话的中间出来@的标记,这个标记将会被当做普通内容而被忽略掉。
@access        该标记用于指明关键字的存取权限:private、public或proteced 使用范围:class,function,var,define,module
@author        指明作者
@copyright    指明版权信息
@const        使用范围:define 用来指明php中define的常量
@final            使用范围:class,function,var 指明关键字是一个最终的类、方法、属性,禁止派生、修改。
@global        指明在此函数中引用的全局变量
@name            为关键字指定一个别名。
@package    用于逻辑上将一个或几个关键字分到一组。
@abstrcut    说明当前类是一个抽象类
@param        指明一个函数的参数
@return        指明一个方法或函数的返回值
@static            指明关建字是静态的。
@var            指明变量类型
@version        指明版本信息
@todo            指明应该改进或没有实现的地方
@link            可以通过link指到文档中的任何一个关键字
@ingore        用于在文档中忽略指定的关键字

一些注释规范
a.注释必须是
/**
* XXXXXXX
*/
的形式
b.对于引用了全局变量的函数,必须使用glboal标记。
c.对于变量,必须用var标记其类型(int,string,bool...)
d.函数必须通过param和return标记指明其参数和返回值
e.对于出现两次或两次以上的关键字,要通过ingore忽略掉多余的,只保留一个即可
f.调用了其他函数或类的地方,要使用link或其他标记链接到相应的部分,便于文档的阅读。
g.必要的地方使用非文档性注释(PHPDOC无法识别的关键字前的注释),提高代码易读性。
h.描述性内容尽量简明扼要,尽可能使用短语而非句子。
i.全局变量,静态变量和常量必须用相应标记说明

能够被phpdoc识别的关键字:
Include
Require
include_once
require_once
define
function
global
class

3. 规范注释的php代码 :

<?php
/**
* 文件名(sample2.php)
*
* 功能描述(略)
*
* @author steve <liuzhiqun@facedoing.com>
* @version 1.0
* @package sample2
*/

/**
* 包含文件
*/
include_once 'sample3.php';

/**
* 声明全局变量
* @global integer $GLOBALS['_myvar']
* @name $_myvar
*/
$GLOBALS['_myvar'] = 6;

/**
* 声明全局常量
*/
define('NUM', 6);

/**
* 类名
*
* 类功能描述
*
* @package sample2
* @subpackage classes(如果是父类 就添加)
*/
class myclass {

/**
* 声明普通变量
*
* @accessprivate
* @var integer|string
*/
var $firstvar = 6;

/**
* 创建构造函数 {@link $firstvar}
*/
function myclass() {
$this->firstvar = 7;
}

/**
* 定义函数
*
* 函数功能描述
*
* @global string $_myvar
* @staticvar integer $staticvar
* @param string $param1
* @param string $param2
* @return integer|string
*/
function firstFunc($param1, $param2 = 'optional') {
static $staticvar = 7;
global $_myvar;
return $staticvar;
}
}
?>