PHP 정의 상수에 대한 자세한 설명

WBOY
풀어 주다: 2016-07-25 08:53:25
원래의
1665명이 탐색했습니다.
  1. 클래스 A {
  2. 공용 함수 __toString() {
  3. return 'bar';
  4. }
  5. }
  6. $a = new A();
  7. define('foo', $a);
  8. echo foo;
  9. // 출력 표시줄
코드 복사

PHP에서 정의는 어떻게 구현됩니까?

  1. ZEND_FUNCTION(define)

  2. {
  3. char *name;
  4. int name_len;
  5. zval *val;
  6. zval *val_free = NULL;
  7. zend_bool non_cs = 0;
  8. int case_sensitive = CONST_CS;
  9. zend_constant c;

  10. 매개변수, 문자열, zval, bool

  11. if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
  12. return;
  13. }< p>
  14. // 대소문자를 구분하나요?

  15. if(non_cs) {
  16. case_sensitive = 0;
  17. }

  18. 클래스 상수를 정의하면 오류가 보고됩니다.

  19. if (zend_memnstr(name, "::", sizeof("::") - 1, name name_len)) {
  20. zend_error(E_WARNING, "클래스 상수는 다음과 같을 수 없습니다. 정의 또는 재정의됨 ");
  21. RETURN_FALSE;
  22. }

  23. // 실제 값을 가져와서 val

  24. repeat:
  25. 스위치로 저장합니다(Z_TYPE_P( val)) {
  26. 케이스 IS_LONG:
  27. 케이스 IS_DOUBLE:
  28. 케이스 IS_STRING:
  29. 케이스 IS_BOOL:
  30. 케이스 IS_RESOURCE:
  31. 케이스 IS_NULL:
  32. 중단;
  33. 케이스 IS_OBJECT :
  34. if (!val_free) {
  35. if (Z_OBJ_HT_P(val)->get) {
  36. val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
  37. 반복 이동 ;
  38. } else if (Z_OBJ_HT_P(val)->cast_object) {
  39. ALLOC_INIT_ZVAL(val_free);
  40. if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == 성공 ) {
  41. val = val_free;
  42. break;
  43. }
  44. }
  45. }
  46. /* 중단 없음 */
  47. 기본값:
  48. zend_error(E_WARNING,"상수는 다음과 같습니다. 스칼라 값으로만 ​​평가됩니다.");
  49. if (val_free) {
  50. zval_ptr_dtor(&val_free);
  51. }
  52. RETURN_FALSE;
  53. }
  54. // 구성 상수
  55. c.value = *val;
  56. zval_copy_ctor(&c.value);
  57. if (val_free) {
  58. zval_ptr_dtor(&val_free);
  59. }
  60. c.flags = case_sensitive /* 비지속적; */ // 대소문자를 구분하지 않으면 0, 대소문자를 구분하면 1입니다
  61. c.name = zend_strndup(name, name_len);
  62. c.name_len = name_len 1;
  63. c.module_number = PHP_USER_CONSTANT; // 주석 커널 상수가 아니라 사용자 정의 상수
  64. // 상수 등록
  65. if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {
  66. RETURN_TRUE;
  67. } else {
  68. RETURN_FALSE ;
  69. }
  70. }

코드 복사

주의하세요 반복으로 시작하는 루프, goto 문도 사용됩니다 T_T

이 코드의 기능은 다음과 같습니다. int, float, string, bool, Resource, null의 경우 실제로 상수를 정의할 때 이 값을 직접 사용하세요. 객체의 경우 위 6가지 유형 중 하나로 객체를 변환해야 합니다. (변환 후에도 여전히 객체인 경우 변환을 계속합니다.) 객체를 6가지 유형 중 하나로 변환하는 방법은 무엇입니까? 코드 관점에서는 두 가지 방법이 있습니다.

  1. if (Z_OBJ_HT_P(val)->get) {
  2. val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
  3. gotopeat;
  4. }
  5. // __toString() 메서드는 Cast_object에서 호출됩니다.
  6. else if (Z_OBJ_HT_P(val)->cast_object) {
  7. ALLOC_INIT_ZVAL(val_free);
  8. if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS)
  9. {
  10. val = val_free;
  11. break;
  12. }
  13. }
코드 복사

1, Z_OBJ_HT_P(val)->get, 매크로 확장 후 (*val).value.obj.handlers->get

2, Z_OBJ_HT_P(val)->cast_object, 매크로 확장 후는 (*val).value.obj.handlers->cast_object

핸들러는 많은 함수 포인터를 포함하는 구조입니다. 구체적인 정의는 _zend_object_handlers를 참조하세요. 이 구조의 함수 포인터는 객체 속성 읽기/수정, 객체 메소드 획득/호출 등과 같은 객체를 조작하는 데 사용됩니다. get 및 Cast_object도 그 중 하나입니다.

일반 객체의 경우 PHP는 표준 Cast_object 함수 zend_std_cast_object_tostring을 제공하며 코드는 php-src/zend/zend-object-handlers.c에 있습니다.

  1. ZEND_API int zend_std_cast_object_tostring(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */

  2. {
  3. zval *retval;
  4. zend_class_entry *ce;

  5. 스위치(유형) {

  6. 케이스 IS_STRING:
  7. ce = Z_OBJCE_P(readobj);
  8. // 사용자 클래스에 __toString이 정의되어 있으면
  9. if (ce->__tostring &&
  10. (zend_call_method_with_0_params(&readobj, ce, &ce->__tostring, "__tostring" , &retval) || EG(예외))) {
  11. }
  12. 반환 FAILURE;
  13. }
  14. 반환 FAILURE;
  15. }
  16. < ;/p>
코드 복사

위의 특정 구현에서 기본 Cast_object는 클래스에서 __tostring 메서드를 찾은 다음 호출하는 것입니다. ..

초기 예시인 Define('foo', $a)로 돌아가면, $a는 A의 인스턴스이고 __toString은 클래스 A에 정의되어 있으므로 foo 상수는 실제로 toString의 반환 값 bar와 같습니다. .

ps: 계속해서 세세한 부분까지 파헤쳐 보세요.

1, 정의에는 반환 값이 있습니다. 일반적으로 우리는 상수를 다음과 같이 직접 정의합니다: Define('foo', 123); 그러나 정의의 구현으로 판단하면 반환 값이 있습니다. 설명서의 설명에 따르면:

성공하면 TRUE를 반환하고, 실패하면 FALSE를 반환합니다.

어떤 상황에서 실패를 정의하나요? 예를 들어:

  1. define('PHP_INT_MAX', 1) // FALSE를 반환합니다

  2. define ('FOO', 1); // TRUE 반환

  3. define('FOO', 2); // FALSE 반환
코드 복사

위 코드에는 두 가지 상황이 포함되어 있습니다. 하나는 PHP_INT_MAX와 같이 사전 정의된 PHP 커널 상수를 재정의하려고 시도하는 것입니다. 이는 분명히 실패합니다. 두 번째 경우는 코드 어딘가에 상수 FOO를 정의한 후 다음 프로그램에서 다시 정의하여 실패를 일으키는 경우입니다. 따라서 코딩할 때 이름이 중복되지 않도록 정의해야 하는 상수를 모두 함께 작성하는 것이 가장 좋습니다.

2, 상수 이름에는 제한이 없습니다. 이름이 XXX::YYY 형식인지 여부만 결정하는 정의의 구현을 다시 검토해 보겠습니다.

즉, Define에는 이름에 대한 요구 사항이 거의 없으며, 물론 이름이 합법적인 PHP 변수 이름일 필요도 없습니다. 그러므로 정의의 상수에 이상한 이름을 붙일 수 있습니다. 예를 들어:

  1. define('>_<', 123); // TRUE 반환
  2. echo >_<; // 구문 오류
코드 복사
단, 이러한 상수를 정의하면 직접 사용할 수 없으며 구문 오류가 보고됩니다. 올바른 사용법은 다음과 같습니다.

  1. define('>_<', 123); // TRUE 반환
  2. 에코 상수('>_<'); 출력 123
코드 복사

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿