2024年PHP日本大会

类/对象函数

目录

添加注释

用户贡献的注释 17条注释

gateschris at yahoo dot com
23年前
[编辑注:如果您尝试进行覆盖,您可以直接查询(可能在方法本身中)对象所属的类 (get_class()),或者它是否是特定根类的子类。

您可以始终引用父级被覆盖的方法,请参阅手册中的“类和对象”页面以及其中的注释/编辑说明。]

没有函数可以确定成员是属于基类还是当前类,例如

<?php
class foo {
function
foo () { }
function
a () { }
}

class
bar extends foo {
function
bar () { }
function
a () { }
}

lala = new Bar();
?>
------------------
我们如何以编程方式查找成员a现在属于类Bar还是Foo。
covertka at muohio dot edu
19年前
致 pillepop2003 at yahoo dot de

我也有同样的问题。我有一个基类,它为许多子类管理数据库任务。基类中的一个函数是 find() 方法,它返回子类的实例。由于 find() 通常作为静态方法调用,它需要知道子类的名称。正如您发现的那样,这似乎无法以简单的方式获得。

我发现获取子类名称的唯一方法是使用 debug_traceback() 函数。这要求我在每个子类中都有一个 find() 方法,但它确实有效。

这是一个例子

<?php
require_once("Application.php");

class
parentClass {
function
find() {
$className = NULL;
foreach (
debug_backtrace() as $bt) {
if (
$bt['function'] == __FUNCTION__) {
$className = $bt['class'];
}
}

//此处应有一些代码来查找正确的ID,让我们假设它是ID 1
$id = 1;
return new
$className($id);
}
}

class
foo extends parentClass {
function
__construct($id) {
$this->id = id;
}

function
find() {
return
parent::find();
}
}

class
bar extends parentClass {
function
__construct($id) {
$this->id = id;
}

function
find() {
return
parent::find();
}
}

$a = foo::find();
printf("Type for \$a: %s<br/>\n", get_class($a));
$b = bar::find();
printf("Type for \$b: %s<br/>\n", get_class($b));
?>
asommer*at*as-media.com
22年前
我刚刚发现的一些对我的当前项目非常有用的东西

可以在任何方法(包括构造函数)中让一个类覆盖自身,如下所示

class a {

..function ha ( ) {
....if ( $some_expr ) {
......$this = new b;
......return $this->ha ( );
....}
....return $something;
..}

}

在这种情况下,假设类b已经定义并且也具有方法ha ( )

请注意,覆盖自身后的代码仍然会执行,但现在适用于新类

我在任何地方都没有找到关于此行为的任何信息,所以我不知道这是否应该这样,以及它是否可能会改变……但它在灵活的脚本编写中打开了一些可能性!!
zidsu at hotmail dot com
21年前
仅供参考:如果您想将您的类拆分成可管理的块,这意味着对您来说是不同的文件,您可以将您的函数放入包含文件中,并使 include() 具有返回值。像这样

class Some_class {
var $value = 3;
function add_value ($input_param) {
return include ("path/some_file.php");
}
}

以及您的包含文件

$input_param += $this->value;
return $input_param;

然后您的函数调用将是

$instance = new Some_class ();
$instance->add_value (3);

这将返回
6
希望如此 :P

但请记住,包含文件中的作用域将与函数“add_value”的作用域相同。
如果您想返回结果,也应该在您的 include 中进行 return 语句。
http://sc.tri-bit.com/ StoneCypher
19年前
邮件发送至 covertka at muohio dot edu 和 pillepop2003 at yahoo dot de

对于使用工厂函数获取类名,有一个更简单的解决方案。假设你正在做类似这样的事情:

<?php

function FactoryFunction($whatever, $instancedata) {

switch (
$whatever) {
case
'stuff' : return new Stuff($instancedata);
case
'otherstuff' : return new Otherstuff($instancedata);
}

}

?>

现在,考虑命名参数习惯用法,并记住PHP对所有内容都使用哈希;因此,进行以下更改:

<?php

function FactoryFunction($whatever, $instancedata) {

switch (
$whatever) {

case
'stuff' : return array('typeis'=>'stuff', 'instance'=>new Stuff($instancedata));
case
'otherstuff' : return array('typeis'=>'otherstuff', 'instance'=>new Otherstuff($instancedata));

}

}

?>

简洁明了。原发帖人似乎想要的是类似于C++静态数据成员的东西;不幸的是,由于PHP4根本没有静态变量,因此需要对语言进行重大更改才能支持类似静态的行为。如果你迁移到PHP5,static关键字可以干净利落地解决你的问题。
ettinger at consultant dot com
20年前
主题:寻找未实例化的类

# 将数据从表加载到类对象中
class LFPDataFactory extends LFPObject {
var $object;
var $class;
var $table;
function LFPDataFactory($args) {
$this->unpackArgs($args); // 从$args分配局部变量
if (in_array(strtolower($this->class), get_declared_classes())) {
$this->object = new $this->class;
// 组装表中的列……
// 选择它们的值并将其放入我们的新对象……
} else { trigger_error("未找到类 ".$this->class, E_USER_ERROR); }
}
}
$r = new LFPDataFactory("class=LFPLayout,table=layout");
$new_obj = $r->object; // 这是一个LFPLayout对象。
print_r($new_obj);

此类检查类是否存在,然后实例化它——已声明的类与已实例化的类不同。只要LFPLayout存在于脚本中的某个地方,get_declared_classes() 就会找到它。但是,请记住在比较时使用strtolower。

我为什么要这样做?因为我的类布局与它们各自的表相同;然后,工厂选择数据(确保变量匹配)并将数据插入。(我已经省略了执行选择/插入的实际代码)。
Dennis
14年前
我们有一个数组,其中包含许多类似风格的对象:

<?php

$step
= new StepModel(1); // 如果StepModel id 为 "1"
$demand = $step->getDemand(); // 返回DemandModel
$step2 = $demand->getCustomer(); // 返回StepModel
$demand2 = $step2->getDemand(); // 返回DemandModel

// [ ... ]

?>

$step 和 $step2 可以是相同的对象。因此我们有一个递归数组。现在我们需要知道 $step == $step2 还是 $step === $step2。换句话说:我们需要知道PHP内部资源 ID。

因为PHP API中没有此功能,所以我们创建了以下函数。

小心:在我们的例子中,所有对象都具有第一个属性 ["id":protected]。如果你的对象与此不同,则需要编辑 $pattern。

警告:此函数非常慢,只应在调试时需要时调用。

<?php

/**
* 返回数组中所有对象的资源 ID 和对象 ID
*
* @param array $array
* @return array
*/
function getObjectInformation(Array $array)
{
// 开始输出缓冲
ob_start();

// 创建 $array 的 var_dump
var_dump($array);

// 将转储保存到变量 $dump 中
$dump = ob_get_contents();

// 清理输出缓冲区
ob_end_clean();

// 删除空格
$dump = str_replace(' ', '', $dump);

// 定义正则表达式模式
// 在我们的例子中,所有对象都像这样:
//
// object(ClassName)#1(1){
// ["id":protected]=>
// string(1)"1"
$pattern = '/object\(([a-zA-Z0-9]+)\)#([0-9]+)\([0-9]+\){\\n';
$pattern .= '\["id":protected\]=>\\n';
$pattern .= 'string\([0-9]+\)"([v]?[0-9]+)"/im';

// 搜索所有匹配项
preg_match_all($pattern, $dump, $regs);

// 按类名、对象 ID,然后按资源 ID 对所有匹配项进行排序
array_multisort($regs[1], SORT_ASC, SORT_STRING,
$regs[3], SORT_ASC, SORT_NUMERIC,
$regs[2], SORT_ASC, SORT_NUMERIC);

// 缓存最后一次匹配
$lastMatch = array();

// 返回值
$return = array();

// 循环遍历匹配项
for ($i = 0; $i < sizeof($regs[0]); $i ++) {

// 检查当前匹配项是否以前没有访问过
if (0 == sizeof($lastMatch) ||
$regs[1][$i] != $lastMatch[1] ||
$regs[2][$i] != $lastMatch[2] ||
$regs[3][$i] != $lastMatch[3]) {

// 将匹配项保存到返回值中
array_push($return, array($regs[1][$i],
$regs[2][$i],
$regs[3][$i]));
}

// 将匹配项保存到上次匹配缓存中
$lastMatch[1] = $regs[1][$i];
$lastMatch[2] = $regs[2][$i];
$lastMatch[3] = $regs[3][$i];
}

// 返回所有匹配项
return $return;
}

?>

我知道,这不太优雅,但我希望它对一些人有用。
einhverfr at not-this-host dot hotmail dot com
22年前
在复杂的项目中,你可能会发现为你的类使用命名空间并以分层方式安排它们很有帮助。一个简单的做法是使用文件系统来组织你的层次结构,然后定义一个这样的函数:

function use_namespace($namespace){

require_once("namespaces/$namespace.obj.php");

}

(由于此页面的HTML UI导致缩进缺失)
这要求所有对象库都以.obj.php结尾(我使用的是这种方式),但你可以根据需要修改它。例如,你可以这样调用它:

use_namespace("example");
或者,如果foo是example的一部分,你可以调用:
use_namespace("example/foo");
pascal dot poncet at netconsult dot com
19年前
主题:在MySQL查询中使用“sql_calc_found_rows”同时在PHP数据库类对象中利用结果。

您好,

MySQL中有一个很好的函数,允许知道如果没有设置“where”子句,将返回多少条记录:SQL_CALC_FOUND_ROWS。

如果你创建了一个数据库对象来收集返回的行,那么在尝试调用此函数的结果时,你会有点困惑。

为什么?
简单来说,因为返回字段的名称是“found_rows()”,显然不可能像这样调用:

<?php $result->found_rows() ?>

...因为它试图访问一个方法,而不是一个属性!

那么,获得正确结果的唯一方法似乎是使用类函数,例如:

<?php
$db
->query("select found_rows()");
$count=current(get_object_vars(current($db->result)));
?>

当然,如果有人找到了其他解决方法,例如特殊的语法(参见字符串中使用带花括号的数组的语法),我非常乐意讨论。

祝你好运!
Pascal
[email protected]
16年前
要访问名称中包含非法字符的对象成员,请使用此语法:

$obj->{'illegal-property:name()'}

这对于例如数据库对象和SoapClient类使用的动态生成的类尤其相关。
Skydev
13年前
一个小的函数,允许查找对对象的全部引用。在3分钟内编写,可能存在错误(例如,在某些地方将对象作为引用传递?)。

<?php
function find_ref_obj($object, $obj, $path) {
if (
in_array($obj,$GLOBALS['__REF_CHECKED'],true))
return
false;
$GLOBALS['__REF_CHECKED'][]=$obj;
$r = array();
foreach ((array)
$obj as $k => $v) {
if (
$v === $object)
$r[] = $path . "->$k";
if (
is_object($v)) {
$t = find_ref_obj($object,$v,$path . "->$k");
if (
$t!==false)
$r=array_merge($r,$t);
}
else if (
is_array($v)) {
$t = find_ref_arr($object,$v,$path . "->$k");
if (
$t!==false)
$r=array_merge($r,$t);
}
}
if (empty(
$r))
return
false;
else
return
$r;
}
function
find_ref_arr($object, $arr, $path) {
if (
in_array($arr,$GLOBALS['__REF_CHECKED'],true))
return
false;
$GLOBALS['__REF_CHECKED'][]=$arr;
$r = array();
foreach (
$arr as $k => $v) {
if (
$v === $object)
$r[] = $path . "['$k']";
if (
is_object($v)) {
$t = find_ref_obj($object,$v,$path . "['$k']");
if (
$t!==false)
$r=array_merge($r,$t);
}
else if (
is_array($v)) {
$t = find_ref_arr($object,$v,$path . "['$k']");
if (
$t!==false)
$r=array_merge($r,$t);
}
}
if (empty(
$r))
return
false;
else
return
$r;
}
function
find_references($object) {
$r = array();
$GLOBALS['__REF_CHECKED']=array();
foreach (
$GLOBALS as $n => $v)
if (
$n!='__REF_CHECKED')
if (
$n!='GLOBALS') {
if (
$v === $object)
$r[]=$n;
if (
is_object($v)) {
$t = find_ref_obj($object,$v,$n);
if (
$t!==false)
$r=array_merge($r,$t);
}
else if (
is_array($v)) {
$t = find_ref_arr($object,$v,$n);
if (
$t!==false)
$r=array_merge($r,$t);
}
}
unset(
$GLOBALS['__REF_CHECKED']);
return
$r;
}

function
find_refs($object) {
return
implode(', ',find_references($object));
}
?>
HOC
20年前
致 pillepop2003

你为什么想知道一个不存在的对象的类名?

对我来说,这个问题唯一的解释是你想要在实例化对象之前知道它的类。但这毫无用处,因为你总是实例化你选择的类。

当类被实例化为对象时,你可以通过`get_class()`方法找到该对象的类。这就是你需要的一切。在继承的情况下,你可以使用`get_class($this)`来获取实例化对象的类。现在你可以根据对象所属的类进行区分。

例如:

<?php
class A{
function
A(){
$class_of_this = get_class($this);
echo
'Object is an instance of class '.$class_of_this.' which is the ';
if(
strcmp($class_of_this,'A')==0)
echo
'parent-class';
else if(
strcmp($class_of_this,'B')==0)
echo
'child-class';
echo
".\n";
}
}

class
B extends A{
function
B(){
$this->A();
}
}

$object1 = new A();
$object2 = new B();
?>

运行此代码片段,输出将是:

Object is an instance of class A which is the parent-class.
Object is an instance of class B which is the child-class.
[email protected]
19年前
((PHP5))

我想为一个类动态选择一个扩展。这花了我一段时间来尝试,但我找到了一个解决方案。请注意,我无法验证它的安全性,但它似乎对我有用。也许其他人可以阐明细节。

<?php

A { var $value = "类 A\n"; }
B { var $value = "类 B\n"; }

// 取消您想要扩展的注释。您也可以使用变量。
// define('__EXTENDER__', 'A');
define('__EXTENDER__', 'B');

// 使用 eval 创建包装器类。
eval('类 EXTENDER extends '. __EXTENDER__ . ' { }');

C extends EXTENDER
{
function
__construct()
{
echo
$this->value;
}
}

$t = new C;

?>

输出:类 B

实际应用:我有一个数据库抽象系统,它为 mysql、pgsql 等创建了单独的类。我希望能够创建一个全局 db 类,该类根据应用程序配置扩展单个 db 类之一。

我知道可能有更好的方法来做到这一点,但我还没有达到关于类的那个水平。
justin at quadmyre dot com
22年前
如果您想能够从另一个类中调用类的实例,您只需将对外部类的引用存储为局部类的属性(可以使用构造函数将此传递给类),然后像这样调用外部方法

$this->classref->memberfunction($vars);

或者,如果双“->” 对您来说太奇怪了,那么试试这个

$ref=&$this->classref;
$ref->memberfunction($vars);

如果您编写类似于通用 SQL 类的东西,您希望其他类中的成员函数能够使用,但又希望保持命名空间分离,这将非常方便。希望这对某人有所帮助。

Justin

示例

<?php

class1 {
function
test($var) {
$result = $var + 2;
return
$result;
}
}

class2{
var
$ref_to_class=''; # 将指向其他类

function class1(&$ref){ #构造函数
$this->ref_to_class=$ref; #将对其他类的引用保存为此类的属性
}

function
test2($var){
$val = $this->ref_to_class->test($var); #使用引用调用其他类
return $val;
}
}

$obj1=new class1;
# 实例化 obj1。
$obj2=new class2($obj1);
# 实例化 obj2 时传递对 obj1 的引用

$var=5;
$result=obj2->test2($var);
# 调用 obj2 中的方法,该方法调用 obj1 中的方法
echo ($result);

?>
greg at doutromundo dot com
20年前
作为程序员,您可能比我更有条理,但我确实尝试在我的类和代码中保持一定的顺序,并将它们像 Java 中那样分离到“包”中。
这帮助我保持它们的组织性,但在尝试使用它们时却造成了混乱,所以我所做的是创建一个处理类加载的类(我在所有页面中都实例化它),以及我捆绑在一起的错误处理类。这样,我可以使用类似于以下命令的命令加载我的类:
$baseClass->loadClass("package","className"[,"constructor"]);

负责此功能的函数会进行一些检查,以查看它们是否已加载等等……

function loadClass($packageName,$className,$constructor=""){
// 如果您没有构造函数,请在类中声明任何函数
// 类
if ($constructor==""){
$constructor=$className;
}
if(!is_callable(array($className,$constructor))){
if (defined("CLASS_DIR")){
$pkg = CLASS_DIR.$packageName."/";
if (is_dir($pkg)){
// 我们有一个包含包名称的目录
$cls = $pkg.$className.".class.php";
if(is_file($cls)){
// 我们有一个文件
include_once($cls);
}else{
die("类 <b>$className</b> 在包 <b>$packageName</b> 中找不到,请检查您的安装");
}
}else{
die("找不到包 <b>$packageName</b>,请检查您的安装");
}
}
}
}

请记住将 CLASS_DIR 定义为包所在目录的物理路径……

希望这对您有所帮助……

这是一个目录结构的示例……
/var/www/classes/ <- 这将是 CLASS_DIR
在那里我有
package1/
name.class.php
name2.class.php
....

loadClass 将如下所示:loadClass("package1","name");

简洁易用
cjones
19年前
如果有人有兴趣寻找一种将现有对象动态加载到类中的方法,这是我发现非常有用的方法。

//---------------------------------------------------------
// 将外部对象动态加载到类中

function objRef ( &$obj ) {
eval("\$this->obj_".get_class($obj)." = \$obj;");
}
//---------------------------------------------------------
// 使用以下方法引用:$this->obj_[对象名称]->[var|f{}]

示例

class date { function date ( ) { $this->date = "March 3rd"; } }
class time { function time ( ) { $this->time = "12:30pm"; } }

class show {
function objRef ( &$obj ){
eval("\$this->obj_".get_class($obj)." = \$obj;");
}
function test ( $var ){
echo "$var".$this->obj_date->date." @ ".$this->obj_time->time;
}
}

$date = new date;
$time = new time;
$show = new show;
$show->objRef($date);
$show->objRef($time);
$show->test("Time Now => ");

// 输出:Time Now => March 3rd @ 12:30pm

我发现类名前缀“obj_”很有用,因为它帮助我在扫描脚本时自动识别外部对象引用。如果需要,您可以省略此项。希望这对某人有所帮助。
ia [AT] zoznam [DOT] sk
19年前
关于 zabmilenko 的解决方案
这样创建是否更好?

<?php
// 所有 db 类的基类
DB {
protected
$connectId;
}

// MySQL 类,它扩展了基类
MySQL extends DB {
function
connect () {
$this->connectId = mysql_connect (...);
}
}

// PostgreSQL 类,它扩展了基类
pgSQL extends DB {
function
connect () {
$this->connectId = pg_connect (...);
}
}

// 然后像这样调用构造函数:
$dbName = "MySQL";
$db = new $dbName ( ... );
// ... 这将创建一个 MySQL 类的对象
?>
To Top