PHP Conference Japan 2024

類別/物件函式

目錄

新增註解

使用者貢獻的註解 17 則註解

11
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。
4
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));
?>
3
asommer*at*as-media.com
22 年前
我剛剛發現的一些東西,對於我目前專案非常方便

類別可以在任何方法(包括建構函式)中覆寫自己,如下所示

class a {

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

}

在這種情況下,假設類別 b 已經定義,並且也有 ha ( ) 方法

請注意,在覆寫自身的陳述之後的程式碼仍然會執行,但現在適用於新的類別

我沒有在任何地方找到有關此行為的任何資訊,所以我不知道這是否應該是這樣,以及它是否可能會改變... 但是它在彈性腳本中開啟了一些可能性!!
2
zidsu at hotmail dot com
21 年前
FYI:如果您想要將類別分割成可管理的小區塊,這表示您使用不同的檔案,您可以將函式放入 include 中,並讓 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` 函數的作用域相同。
如果您想要回傳結果,您也應該在包含檔案中加入 return 陳述式。
0
http://sc.tri-bit.com/ StoneCypher
19 年前
寄給 covertka 在 muohio 點 edu 和 pillepop2003 在 yahoo 點 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,靜態關鍵字就能完美地解決您的問題。
0
ettinger 在 consultant 點 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。

我為什麼要這樣做?因為我的類別配置與其各自的資料表相同;工廠接著會選取資料(確保變數相符)並插入資料。(我省略了執行選取/插入的實際程式碼)。
-1
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 中
$dump = ob_get_contents();

// 清除輸出緩衝區
ob_end_clean();

// 刪除空白字元
$dump = str_replace(' ', '', $dump);

// 定義 regex 模式
// 在我們的案例中,所有物件看起來都像這樣:
//
// 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;
}

?>

我知道這不是那麼優雅,但我希望它對一些人有用。
-1
einhverfr 在 not-this-host 點 hotmail 點 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");
-3
pascal dot poncet at netconsult dot com
19 年前
主旨:在 PHP 資料庫類別物件中利用結果時,於 MySQL 查詢中使用 "sql_calc_found_rows"。

您好,

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
-4
ahigerd at timeips dot com
16 年前
要存取名稱中包含非法字元的物件成員,請使用以下語法

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

這在使用動態產生的類別時特別相關,例如資料庫物件和 SoapClient 類別。
-4
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));
}
?>
-4
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();
?>

當你執行這段程式碼片段時,輸出將會是:

物件是父類別 A 的實例。
物件是子類別 B 的實例。
-3
zabmilenko at hotmail dot com
19 年前
((PHP5))

我想要動態地為一個類別選擇擴展器。這花了我一些時間摸索,但我找到了一個解決方案。請注意,我無法驗證它的安全性,但它對我來說似乎是有效的。或許其他人可以闡明其中的細節。

<?php

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

// 取消註解你想要的擴展器。你也可以使用變數。
// define('__EXTENDER__', 'A');
define('__EXTENDER__', 'B');

// 使用 eval 來建立一個包裝類別。
eval('class EXTENDER extends '. __EXTENDER__ . ' { }');

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

$t = new C;

?>

輸出:Class B

實際應用:我有一個資料庫抽象系統,針對 mysql、pgsql 等有各自的類別。我希望能夠建立一個全域的 db 類別,根據應用程式的設定來擴展其中一個個別的 db 類別。

我知道可能還有更好的方法來做到這一點,但我在類別方面還沒達到那個程度。
-4
justin at quadmyre dot com
22 年前
如果你想要能夠從另一個類別中呼叫一個類別的實例,你只需要將外部類別的參考儲存為本地類別的一個屬性(可以使用建構子將其傳遞給類別),然後像這樣呼叫外部方法:

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

或者如果雙重 '->' 對你來說太奇怪,那這樣如何:

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

如果你寫了一些通用的 SQL 類別,而你希望其他類別中的成員函數能夠使用它,但又希望保持命名空間分離,這會很方便。希望對某些人有所幫助。

Justin

範例

<?php

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

class
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);

?>
-4
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>$packageName</b> 中找不到類別 <b>$className</b>,請檢查您的安裝");
}
}else{
die("找不到套件 <b>$packageName</b>,請檢查您的安裝");
}
}
}
}

只要記得將 CLASS_DIR 定義為您套件所在目錄的實體路徑...

希望這對您有所幫助...

以下是一個目錄結構的範例...
/var/www/classes/ <- 這將是 CLASS_DIR
在那裡我有
package1/
name.class.php
name2.class.php
....

loadClass 看起來會像這樣:loadClass("package1","name");

可愛又簡單
-5
cjones
19 年前
如果有人有興趣尋找一種將現有物件動態載入類別的方法,以下是我發現非常有用的方法。

//---------------------------------------------------------
// 將外部物件動態載入類別

function objRef ( &$obj ) {
eval("\$this->obj_".get_class($obj)." = \$obj;");
}
//---------------------------------------------------------
// 使用以下方式參考:$this->obj_[物件名稱]->[變數|函式{}]

範例

class date { function date ( ) { $this->date = "3月3日"; } }
class time { function time ( ) { $this->time = "下午12:30"; } }

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("現在時間 => ");

// 輸出:現在時間 => 3月3日 @ 下午12:30

我發現類別名稱前面的前綴「obj_」很有用,因為它幫助我在瀏覽腳本時自動識別外部物件參考。如果你願意,你可以省略它。希望這對某些人有所幫助。
-4
ia [AT] zoznam [DOT] sk
19 年前
關於 zabmilenko 的解決方案
這樣建立會不會更好?

<?php
// 所有 db 類別的基本類別
class DB {
protected
$connectId;
}

// MySQL 的類別,它繼承自基本類別
class MySQL extends DB {
function
connect () {
$this->connectId = mysql_connect (...);
}
}

// PostgreSQL 的類別,它繼承自基本類別
class pgSQL extends DB {
function
connect () {
$this->connectId = pg_connect (...);
}
}

// 然後像這樣呼叫建構子:
$dbName = "MySQL";
$db = new $dbName ( ... );
// ... 這會建立一個 MySQL 類別的物件
?>
To Top