PHP: Lưu trữ 'đối tượng' bên trong $ _SESSION


188

Tôi chỉ cần tìm ra rằng tôi thực sự có thể lưu trữ các đối tượng trong $ _SESSION và tôi thấy nó khá tuyệt vì khi tôi nhảy sang một trang khác tôi vẫn có đối tượng của mình. Bây giờ trước khi tôi bắt đầu sử dụng phương pháp này, tôi muốn tìm hiểu xem nó thực sự là một ý tưởng tốt hay nếu có những cạm bẫy tiềm ẩn liên quan.

Tôi biết rằng nếu tôi có một điểm vào duy nhất thì tôi sẽ không cần phải làm điều đó nhưng tôi vẫn chưa ở đó nên tôi không có một điểm vào nào và tôi thực sự muốn giữ đối tượng của mình vì tôi không ' T mất trạng thái của tôi như thế. (Bây giờ tôi cũng đã đọc rằng tôi nên lập trình các trang web không trạng thái nhưng tôi chưa hiểu khái niệm đó.)

Vì vậy, tóm lại : Có ổn không khi lưu trữ các đối tượng trong phiên, có vấn đề gì với nó không?


Biên tập:

Tóm tắt tạm thời : Đến bây giờ tôi hiểu rằng có lẽ tốt hơn để tạo lại đối tượng ngay cả khi nó liên quan đến việc truy vấn lại cơ sở dữ liệu.

Câu trả lời thêm có thể có thể giải thích về khía cạnh đó nhiều hơn một chút!


13
Tôi đã "ngu ngốc" như thế nào trong năm 2008 :-)
markus

49
nhưng câu hỏi hữu ích cho 'ngu ngốc như chúng ta năm 2014: D
Momin Al Aziz

3
Những câu hỏi rất hay mà bạn đã hỏi markus .. :) Tôi đã đọc nó ngày hôm nay;)
gkd

1
Bạn không ngu ngốc! Bạn hỏi những gì tôi sắp hỏi và làm cho tôi một rắn, 10 năm sau!
chập chững

tốt, tôi đoán bạn vừa cứu tôi khỏi hỏi một câu hỏi ngu ngốc vào năm 2019
Maxwell

Câu trả lời:


133

Tôi biết chủ đề này đã cũ, nhưng vấn đề này liên tục xuất hiện và chưa được giải quyết cho sự hài lòng của tôi:

Cho dù bạn lưu các đối tượng trong $ _SESSION hoặc tái cấu trúc toàn bộ chúng dựa trên dữ liệu được lưu trong các trường mẫu ẩn hoặc truy vấn lại chúng từ DB mỗi lần, bạn đang sử dụng trạng thái. HTTP là không trạng thái (nhiều hơn hoặc ít hơn, nhưng xem GET so với PUT) nhưng hầu hết mọi thứ mà bất kỳ ai quan tâm với ứng dụng web đều yêu cầu trạng thái phải được duy trì ở đâu đó. Hành động như thể đẩy nhà nước vào các ngóc ngách lên tới một số loại chiến thắng lý thuyết là sai. Nhà nước là nhà nước. Nếu bạn sử dụng trạng thái, bạn sẽ mất các lợi thế kỹ thuật khác nhau có được do không trạng thái. Đây không phải là một cái gì đó để mất ngủ trừ khi bạn biết trước rằng bạn nên mất ngủ vì nó.

Tôi đặc biệt bối rối bởi những lời chúc phúc nhận được từ những lý lẽ "gấp đôi" do Hank Gay đưa ra. OP có đang xây dựng một hệ thống thương mại điện tử phân tán và cân bằng tải không? Tôi đoán là không; và tôi sẽ tiếp tục khẳng định rằng việc tuần tự hóa lớp Người dùng $ của anh ấy, hoặc bất cứ điều gì, sẽ không làm tê liệt máy chủ của anh ấy sau khi sửa chữa. Lời khuyên của tôi: sử dụng các kỹ thuật hợp lý với ứng dụng của bạn. Các đối tượng trong $ _SESSION đều ổn, tuân theo các biện pháp phòng ngừa thông thường. Nếu ứng dụng của bạn đột nhiên biến thành thứ gì đó cạnh tranh với Amazon về lưu lượng truy cập được phục vụ, bạn sẽ cần phải điều chỉnh lại. Đó là cuộc sống.


16
Câu trả lời hay kết hợp rất nhiều suy nghĩ của riêng tôi khi tôi đã đọc qua điều này. Internet hiện đại cần nhà nước. Mặc dù một số ứng dụng không cần trạng thái và có ý nghĩa để thực hiện theo cách không trạng thái, internet hiện đại dựa vào quá nhiều hệ thống dựa trên trạng thái (AKA: Đăng nhập!) Để từ bỏ chúng! Các vị thần vĩ đại của internet thậm chí đã kết hợp khái niệm cơ bản đó trong nhiều năm dưới dạng cookie và ở cấp độ cơ bản, họ đã thêm nó dưới dạng lưu trữ cục bộ trong HTML. Có thể có ý nghĩa để tránh sử dụng quá mức trạng thái trong một số ứng dụng, nhưng một số! = Tất cả!
RonLugge

Chà, khi tôi hỏi câu hỏi đó ngay sau khi con người phát minh ra lửa, tôi đã không biết nhiều thứ tôi biết ngày hôm nay ... điều đó cũng tốt. Trong khi đó, tôi có thể nói rằng có thể có một vài trường hợp sử dụng tốt nhưng nhìn chung tôi sẽ tìm giải pháp khác trước. Vẫn đánh dấu đây là câu trả lời mới được chấp nhận vì câu trả lời khác là phân loại.
markus

Rất ít câu trả lời làm tôi cười thành tiếng. Cái này đã làm. Bravo +1
chập chững

114

Sẽ ổn miễn là vào thời điểm cuộc gọi session_start () được thực hiện, khai báo / định nghĩa lớp đã bị PHP bắt gặp hoặc có thể được tìm thấy bởi trình tải tự động đã cài đặt. nếu không, nó sẽ không thể giải tuần tự hóa đối tượng khỏi kho lưu trữ phiên.


12
Cảm ơn! Điều đó đã sửa một lỗi cho tôi: D
Matt Ellen

Tôi giả định rằng vấn đề này có thể tránh được nếu bạn có một __autoload()chức năng phù hợp .
Langel

Trong việc hủy xác định một đối tượng được tuần tự hóa chúng ta có phải thêm định nghĩa lớp không ??? Tại thời điểm tuần tự hóa đối tượng, nó cần định nghĩa lớp, tôi đồng ý, nhưng tôi có phải thêm định nghĩa lớp trong tệp mà tôi phải hủy xác định đối tượng được tuần tự hóa không ???
Rajesh Paul

35

HTTP là một giao thức phi trạng thái vì một lý do. Phiên trạng thái hàn lên HTTP. Theo nguyên tắc thông thường, tránh sử dụng trạng thái phiên.

CẬP NHẬT: Không có khái niệm về một phiên ở cấp HTTP; máy chủ cung cấp điều này bằng cách cung cấp cho khách hàng một ID duy nhất và yêu cầu khách gửi lại nó theo mọi yêu cầu. Sau đó, máy chủ sử dụng ID đó làm khóa thành một hàm băm lớn của các đối tượng Phiên. Bất cứ khi nào máy chủ nhận được yêu cầu, nó sẽ tra cứu thông tin Phiên từ các đối tượng phiên có thể băm của nó dựa trên ID mà khách hàng đã gửi cùng với yêu cầu. Tất cả công việc làm thêm này là một sự thay đổi gấp đôi về khả năng mở rộng (một lý do lớn khiến HTTP không trạng thái).

  • Whammy One: Nó làm giảm công việc mà một máy chủ có thể làm.
  • Whammy Two: Điều này khiến việc mở rộng quy mô trở nên khó khăn hơn vì bây giờ bạn không thể định tuyến một yêu cầu đến bất kỳ máy chủ cũ nào - tất cả chúng đều không có cùng một phiên. Bạn có thể ghim tất cả các yêu cầu với ID phiên đã cho vào cùng một máy chủ. Điều đó không dễ dàng và đó là một điểm thất bại duy nhất (không phải đối với toàn bộ hệ thống, mà đối với khối lượng lớn người dùng của bạn). Hoặc, bạn có thể chia sẻ bộ lưu trữ phiên trên tất cả các máy chủ trong cụm, nhưng bây giờ bạn có độ phức tạp cao hơn: bộ nhớ gắn mạng, máy chủ phiên độc lập, v.v.

Với tất cả những điều đó, bạn càng đưa nhiều thông tin vào phiên, tác động đến hiệu suất càng lớn (như Vinko chỉ ra). Cũng như Vinko chỉ ra, nếu đối tượng của bạn không tuần tự hóa, phiên sẽ hoạt động sai. Vì vậy, theo nguyên tắc thông thường, tránh đặt nhiều hơn mức cần thiết trong phiên.

@Vinko Bạn thường có thể làm việc xung quanh việc có trạng thái lưu trữ máy chủ bằng cách nhúng dữ liệu bạn đang theo dõi trong phản hồi bạn gửi lại và yêu cầu khách hàng gửi lại, ví dụ: gửi dữ liệu xuống trong một đầu vào ẩn. Nếu bạn thực sự cần theo dõi trạng thái phía máy chủ, có lẽ nó phải ở trong kho dữ liệu sao lưu của bạn.

(Vinko cho biết thêm: PHP có thể sử dụng cơ sở dữ liệu để lưu trữ thông tin phiên và để khách hàng gửi lại dữ liệu mỗi lần có thể giải quyết các vấn đề về khả năng mở rộng tiềm năng, nhưng mở ra một vấn đề lớn về bảo mật mà bạn phải chú ý ngay bây giờ khi khách hàng kiểm soát được tất cả tiểu bang của bạn)


1
Không có khái niệm về một phiên ở cấp HTTP; máy chủ cung cấp điều này bằng cách cung cấp cho khách hàng một ID duy nhất và yêu cầu khách gửi lại nó theo mọi yêu cầu. Sau đó, máy chủ sử dụng ID đó làm khóa thành một hàm băm lớn của các đối tượng Phiên. Sẽ được tiếp tục
Hank Gay

1
Bất cứ khi nào máy chủ nhận được yêu cầu, nó sẽ tra cứu thông tin Phiên từ các đối tượng phiên có thể băm của nó dựa trên ID mà khách hàng đã gửi cùng với yêu cầu. Tất cả công việc làm thêm này là một sự thay đổi gấp đôi về khả năng mở rộng (một lý do lớn khiến HTTP không trạng thái). Sẽ được tiếp tục
Hank Gay

1
Tôi tự hỏi làm thế nào bạn có thể triển khai các ứng dụng phức tạp qua HTTP mà không cần trạng thái hàn bằng cách nào đó
Vinko Vrsalovic

3
vui lòng chỉnh sửa câu trả lời của bạn để bao gồm tất cả các ý kiến. Nó dễ đọc hơn và tốt hơn cho wiki và dù sao tôi cũng không thể chọn câu trả lời của bạn là câu trả lời được chấp nhận, nếu mọi thứ quan trọng đều nằm trong các bình luận. cảm ơn!
markus

6
"Whammy one" Tôi ước tôi có thể hạ thấp điều này nhiều hơn nữa. Biết thời gian của bạn. Một tham chiếu bộ nhớ có giá 100 nano giây, hoặc 0,0001 ms. Vì vậy, việc tìm kiếm trên một hashtable được lưu trữ trong bộ nhớ chính theo nghĩa đen không tốn thời gian. Có O(1)nói với bạn điều gì không? @whammy hai: chỉ không định tuyến ngẫu nhiên tất cả các yêu cầu đến máy chủ ngẫu nhiên? thực hiện vòng tròn và tiếp tục định tuyến đến cùng một máy chủ từ cùng một người dùng. Đây là wow, siêu rõ ràng. Bạn phải quay trở lại với những cuốn sách của mình, cùng với tất cả hơn 30 lượt
upvote

19
  • Các đối tượng không thể được tuần tự hóa (hoặc chứa các thành viên không thể định dạng được) sẽ không xuất hiện trong $ _SESSION như bạn mong đợi
  • Các phiên khổng lồ đặt gánh nặng lên máy chủ (tuần tự hóa và giải nén megs trạng thái mỗi lần rất tốn kém)

Khác hơn là tôi đã thấy không có vấn đề.


9

Theo kinh nghiệm của tôi, nó thường không xứng đáng với bất cứ điều gì phức tạp hơn StdClass với một số thuộc tính. Chi phí không xác định luôn luôn nhiều hơn so với việc tạo lại từ cơ sở dữ liệu được cung cấp Định danh lưu trữ phiên. Nó có vẻ mát mẻ, nhưng (như mọi khi), hồ sơ là chìa khóa.


Bạn có nhận xét gì về hiệu suất giữa việc truy vấn bảng dữ liệu 5x2 ở mỗi yêu cầu so với lưu trữ kết quả trong phiên và sử dụng điều đó không?
nhạcliftsme

6

Tôi sẽ đề nghị không sử dụng nhà nước trừ khi bạn thực sự cần nó. Nếu bạn có thể xây dựng lại đối tượng mà không cần sử dụng phiên làm việc đó. Có các trạng thái trong ứng dụng web của bạn làm cho ứng dụng trở nên phức tạp hơn để xây dựng, đối với mọi yêu cầu bạn phải xem người dùng đang ở trạng thái nào. Tất nhiên, có những lúc bạn không thể tránh sử dụng phiên (ví dụ: người dùng phải đăng nhập trong phiên của mình ứng dụng web). Cuối cùng tôi sẽ đề nghị giữ cho đối tượng phiên của bạn càng nhỏ càng tốt vì nó ảnh hưởng đến hiệu suất để tuần tự hóa và hủy xác định các đối tượng lớn.


Vì vậy, tốt hơn là xây dựng lại đối tượng bao gồm thực hiện lại tất cả các truy vấn cơ sở dữ liệu? Bởi vì một trong những suy nghĩ của tôi khi làm điều này là tôi không phải truy vấn db cho cùng một thứ.
markus

3
Nếu điều quan trọng với bạn là nó sẽ không truy vấn cơ sở dữ liệu một lần nữa, hãy sử dụng bộ nhớ đệm thay vì lưu trữ nó trong phiên. Nhưng xin vui lòng trước khi làm bất cứ điều gì như xây dựng bộ nhớ đệm kiểm tra xem nó thực sự là một hit hiệu suất.
Johnny

Cảm ơn, tôi thực sự nghĩ rằng nó không phải. Tôi chỉ nên truy vấn lại.
markus

4

Bạn sẽ phải nhớ rằng các loại tài nguyên (như kết nối db hoặc con trỏ tệp) sẽ không tồn tại giữa các lần tải trang và bạn sẽ cần phải tạo lại chúng một cách vô hình.

Cũng xem xét kích thước của phiên, tùy thuộc vào cách lưu trữ, bạn có thể có các hạn chế về kích thước hoặc các vấn đề về độ trễ.


0

Tôi cũng sẽ đưa ra khi nâng cấp thư viện phần mềm - chúng tôi đã nâng cấp phần mềm của chúng tôi và phiên bản cũ có các đối tượng trong phiên với tên lớp của phần mềm V1, phần mềm mới đã bị sập khi cố gắng xây dựng các đối tượng trong phiên - như V2 phần mềm không sử dụng các lớp tương tự nữa, nó không thể tìm thấy chúng. Chúng tôi đã phải đưa vào một số mã sửa lỗi để phát hiện các đối tượng phiên, xóa phiên nếu tìm thấy, tải lại trang. Nỗi đau lớn nhất ban đầu khiến bạn phải tái tạo lỗi này khi nó được báo cáo lần đầu tiên (tất cả đều quá quen thuộc, "tốt, nó hoạt động với tôi" :) vì nó chỉ ảnh hưởng đến những người trong và ngoài hệ thống cũ và mới gần đây - tuy nhiên, tốt công việc chúng tôi đã tìm thấy nó trước khi khởi chạy vì tất cả người dùng của chúng tôi chắc chắn đã có các biến phiên cũ trong phiên của họ và có khả năng bị sập cho tất cả,

Dù sao, như bạn đề xuất trong sửa đổi của mình, tôi cũng nghĩ rằng tốt hơn là tạo lại đối tượng. Vì vậy, có thể chỉ cần lưu trữ id và sau đó trên mỗi yêu cầu kéo đối tượng từ cơ sở dữ liệu, sẽ tốt hơn / an toàn hơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.